¿Por qué algunos usuarios citan nombres de clase en Perl?


12

Mirando Type::Tiny, veo que el nombre de la clase en la llamada a Type::Tiny->newse cita en los documentos oficiales,

my $NUM = "Type::Tiny"->new(
   name       => "Number",
   constraint => sub { looks_like_number($_) },
   message    => sub { "$_ ain't a number" },
);

¿Por qué es esto? ¿Es este un mero estilo? ¿Hay ramificaciones de rendimiento para esta práctica?

Respuestas:


7

Toma un ejemplo más simple

package Foo { sub new { die 7  } };
package Bar { sub new { die 42 } };
sub Foo { "Bar" }
Foo->new();

En el ejemplo anterior, la constante se Fooresuelve en "Bar", por lo que esto llama "Bar"->newno "Foo"->new. ¿Cómo se detiene la resolución de la subrutina? Puedes citarlo.

"Foo"->new();

En cuanto a la implicación del rendimiento, las cosas no empeoran al usar una cadena en lugar de una palabra desnuda. He confirmado que el optree generado por O=Deparsees el mismo. Entonces, como regla general, parece que es mejor citar los nombres de clase si valoras la corrección.

Esto se menciona en Programming Perl (lamentablemente en el contexto de la invocación indirecta de métodos )

... así que le diremos que casi siempre puede salirse con un nombre de clase desnudo, siempre que dos cosas sean ciertas. Primero, no hay una subrutina con el mismo nombre que la clase. (Si sigue la convención de que los nombres de subrutinas como newstart minúsculas y los nombres de clase como ElvenRingstart mayúsculas , esto nunca será un problema). En segundo lugar, la clase se cargó con uno de

use ElvenRing;
require ElvenRing;

Cualquiera de estas declaraciones asegura que Perl sabe que ElvenRinges un nombre de módulo, lo que obliga a que cualquier nombre simple como newantes del nombre de la clase ElvenRingse interprete como una llamada al método, incluso si usted declara una newsubrutina propia en el paquete actual.

Y eso tiene sentido: la confusión aquí solo puede ocurrir si sus subrutinas (generalmente en minúsculas) tienen el mismo nombre que una clase (generalmente en mayúsculas). Esto solo puede suceder si viola esa convención de nomenclatura anterior.

tldr; Probablemente sea una buena idea citar sus nombres de clase, si los conoce y valora la corrección sobre el desorden.

Nota al margen: alternativamente, puede detener la resolución de una palabra sin formato a una función fijando ::a al final de la misma, por ejemplo en lo anterior Foo::->new.


Gracias a Ginnz en reddit por señalarme esto , y a Toby Inkster por el comentario (aunque no tenía sentido para mí en la primera lectura).


2
O Foo::->new, como aprendí de ikegami.
mafia

@mob sí, el libro de Perl también menciona eso (explícitamente), ¿no estoy seguro de si debo poner eso allí o no? jajaja
Evan Carroll

@mob También agregué eso, como una nota al pie. Aunque no estoy seguro de que me guste.
Evan Carroll

1
Foo::tiene la ventaja de que avisa si Foono es un paquete existente
Ikegami

1
Probar :: Tiny es un mejor ejemplo que Foo. En el uso de su código, Foo->se puede esperar que sepa que no hay tal subrutina en su paquete. Pero si está utilizando Try :: Tiny y otros módulos externos de cpan / other, ¿quién puede decir si uno de ellos está usando un paquete Try y, de ser así, si hay un sub Tiny en él?
ysth

0

Citar explícitamente el nombre de la clase en lugar de usar una palabra desnuda (que se trata como una cadena) es una de las tres formas de evitar la ambigüedad sintáctica. La sección Métodos de clase de invocación de la documentación de perlobj explica.

Debido a que Perl le permite usar palabras vacías para nombres de paquetes y nombres de subrutinas, a veces interpreta el significado de una palabra incorrecta de manera incorrecta. Por ejemplo, la construcción Class->new()puede interpretarse como 'Class'->new()o Class()->new(). En inglés, esa segunda interpretación se lee como "llamar a una subrutina llamada Class(), luego llamar new()como un método en el valor de retorno de Class()". Si hay una subrutina nombrada Class()en el espacio de nombres actual, Perl siempre interpretará Class->new()como la segunda alternativa: una llamada al new()objeto devuelto por una llamada a Class().

Vea este extraño caso en acción con la demostración a continuación.

#! /usr/bin/env perl

use strict;
use warnings;

sub Type::Tiny { print "Returning Bogus\n" ; return "Bogus" }

sub Type::Tiny::new { print "Type::Tiny::new\n" }

sub Bogus::new { print "Bogus::new\n" }

my $class = "Type::Tiny";

Type::Tiny->new;
Type::Tiny::->new;
"Type::Tiny"->new;
$class->new;

Su salida es

Bogus volviendo
Bogus :: nuevo
Tipo :: Diminuto :: nuevo
Tipo :: Diminuto :: nuevo
Tipo :: Diminuto :: nuevo

El resto de la sección de documentación mencionada anteriormente muestra cómo protegerse contra comportamientos sorprendentes o errores involuntarios.

Puede obligar a Perl a usar la primera interpretación ( es decir , como una llamada a un método en la clase nombrada "Class") de dos maneras. Primero, puede agregar ::a al nombre de la clase:

Class::->new()

Perl siempre interpretará esto como una llamada al método.

Alternativamente, puede citar el nombre de la clase:

'Class'->new()

Por supuesto, si el nombre de la clase está en un escalar, Perl también hará lo correcto:

my $class = 'Class';
$class->new();

Aplicando a su pregunta, todas las llamadas a continuación son equivalentes.

Type::Tiny::->new(  );

"Type::Tiny"->new(  );

my $class = "Type::Tiny";
$class->new(  );

Añadir ::al final tiene la ventaja de producir una advertencia útil. Digamos que accidentalmente escribiste

Type::Tinny::->new;

Eso produce

La palabra sin formato "Tipo :: Tinny ::" se refiere al paquete inexistente en ./try línea 15.
No se puede encontrar el método de objeto "nuevo" a través del paquete "Tipo :: Tinny" (¿tal vez se olvidó de cargar "Tipo :: Tinny"?) En la línea 15.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.