2011-05-24 14 views
10

Decir que tengo un paquete llamado My::Pkg, y que el paquete tiene un método ->new(...) clase para crear instancias de objetos nuevos:En Perl, ¿hay algún daño al crear una subrutina con el mismo nombre que un paquete?

package My::Pkg; 

sub new {bless {@_[1..$#_]} => $_[0]} 

¿Hay algún daño en la definición de la siguiente subrutina:

sub My::Pkg {@_ ? My::Pkg::new('My::Pkg', @_) : 'My::Pkg'} 

Así que alguien podría escribir:

my $obj = My::Pkg one => 1, two => 2; 

En lugar de:

my $obj = My::Pkg->new(one => 1, two => 2); # which still works, but is longer 

Me gusta la concisión del método package-named-constructor-subroutine, pero me interesa saber si hay algún truco escondido en esta técnica que no haya pensado.


Actualización:

herencia funciona correctamente, como se muestra en el ejemplo aquí:

{package a; sub new {say "a::new [@_] ", $_[0]->init}} 
{package b; our @ISA = 'a'; sub init {"(b::init [@_])"}} 
{package a::b; our @ISA = 'b';} 

sub a::b {print "absub [@_], "; 'a::b'} 

# a::b() called with no args, returns 'a::b', which then becomes 'a::b'->new(...) 
a::b->new;   # absub [], a::new [a::b] (b::init [a::b]) 
a::b->new(1, 2, 3); # absub [], a::new [a::b 1 2 3] (b::init [a::b])  

# no call to `a::b()` but otherwise the same: 
'a::b'->new;   # a::new [a::b] (b::init [a::b]) 
'a::b'->new(1, 2, 3); # a::new [a::b 1 2 3] (b::init [a::b]) 

new a::b::;   # a::new [a::b] (b::init [a::b]) 
new a::b:: 1, 2, 3; # a::new [a::b 1 2 3] (b::init [a::b]) 

Curiosamente el único hasta ahora que es diferente es que los 2 siguientes líneas se convierten en errores de sintaxis:

new a::b; 
new a::b 1, 2, 3; 

¿Qué es un error de sintaxis por la misma razón some_undefined_sub some_defined_sub; es uno.

Si se define la subrutina new, se analiza como new(a::b(...)), lo que es normal para dos subrutinas de palabra abierta adyacentes.

Personalmente, estoy bien con new a::b convertirse en un error de sintaxis, la versión sin ambigüedades new a::b:: siempre funcionará como tchrist señala amablemente a continuación.

+0

Parece limpio. Si algo fallara, sería 'some_sub My :: Pkg a => 1, b => 2;'. No es así – ikegami

+0

@ikegami: Ciertamente ** NO ** falla: 'sub X :: Y {morir" X :: Y() llamado \ n "} sub X :: Y :: nuevo {advertir" X :: Y :: new() llamado \ n "} sub nuevo {die" main :: new() called "} $ a = new X :: Y" business "; warn "got $ a"; 'morirá porque llama a' main :: new (X :: Y ("business")) 'como una subrutina en lugar de invocar apropiadamente' X :: Y :: new ("X: : Y "," business "))' como un método. Además, la llamada a la subrutina no respeta la herencia, ya que se considera obligatoria en un mundo OO. – tchrist

+0

Es malo que 'nuevo negocio X :: Y" 'repentinamente signifique algo diferente de' X :: Y-> nuevo ("negocio") '- * que * BTW actualmente significa' X :: Y() - > nuevo ("negocio") 'en lugar de' X :: Y :: nuevo ("X :: Y", "negocio") 'que todos piensan que significa. – tchrist

Respuesta

7

Eso es precisamente por qué existe

$thingie = new Some::Class one => 1, two => 2; 

o

$thingie = new Some::Class:: 
       one => 1, 
       two => 2, 
      ; 

, por lo que sólo tiene que utilizar.

Pero sí, creo que va a obtener usted mismo en toda una serie de problemas, ya que soy la única persona en el mundo que molesta a empaquetar comilla. No tengo tiempo en este momento para profundizar en mi antiguo código de prueba de problemas, pero estoy bastante seguro de que esto finalmente te hará llorar si vas por el camino del que estás hablando.

+0

Hubiera pensado que la sintaxis indirecta del objeto daría lugar a más ambigüedades que esta técnica. Con este método, el identificador 'My :: Pkg' siempre significa' & My :: Pkg() 'a menos que esté en contexto global, donde es la cadena. Me interesaría saber de algún caso de esquina donde esto no sea válido. –

+0

Hay una gran diferencia entre el método que invoca un método y el que llama a una subrutina: ** inheritance **. Al no usar llamadas a métodos, estás rompiendo con el diseño OO. Perl tiene todo tipo de rarezas, de modo que 'Some :: Class' significa' 'Some :: Class" ', y eso es lo que la gente espera que haga. Si crea una función con el nombre del paquete, se enjuagará por completo al tratar de hacer llamadas al método de clase, porque en su lugar llamará a la función tonta. Y, al contrario del mito del culto a los cargamentos populares, no hay absolutamente nada ambiguo con 'METHOD CLASS :: ARGLIST'. – tchrist

+0

Consulte la actualización de la pregunta anterior, la herencia funciona bien. –

4

"Estoy interesado en saber si hay trampas ocultas a esta técnica que no he pensado."

Creo que un error oculto es la falta de consistencia con la forma en que la mayoría de los lenguajes OOP definen constructores. Obviamente, a Perl le gusta su filosofía TMTOWTDI, pero que alguien tenga que actualizar su código más adelante cuando/si no está cerca puede tomar más tiempo para comprender lo que está haciendo su código.

Además, ¿qué ocurre si desea agregar otro constructor?He visto algunas clases donde hay constructores llamados: new, new_from_file, etc. Tal vez no sea el mejor diseño, pero sí aclararon que un objeto se construyó de una manera única.

Cuestiones relacionadas