2009-01-09 10 views
27

muchos años me recuerdan un compañero programador aconsejar a esto:¿Cuál es la diferencia entre los nuevos Some :: Class y Some :: Class-> new() en Perl? Hace

new Some::Class; # bad! (but why?) 

Some::Class->new(); # good! 

Lamentablemente ahora no puedo recordar el/la razón por qué. :(Ambas formas funcionarán correctamente incluso si el constructor no existe realmente en el módulo Some :: Class, sino que se hereda de un elemento primario en alguna parte.

Ninguna de estas formas es igual a Some :: Class :: new(), que no pasará el nombre de la clase como primer parámetro al constructor, por lo que este formulario siempre es incorrecto.

Incluso si las dos formas son equivalentes, encuentro Some :: Class-> new () para ser mucho más claro, ya que sigue la convención estándar para llamar a un método en un módulo, y en perl, el 'nuevo' método no es especial: un constructor podría llamarse cualquier cosa, y new() podría hacer cualquier cosa (aunque por supuesto, generalmente esperamos que sea un constructor).

+0

Otra excelente referencia: [Indirecta pero aún fatal] (http://www.shadowcat.co.uk/blog/matt-s-trout/indirect-but-still-fatal/) – Ether

Respuesta

26

El uso de new Some::Class se denomina invocación de método "indirecto", y es malo porque introduce cierta ambigüedad en la sintaxis.

Una razón por la que puede fallar es si tiene una matriz o un hash de objetos. Se podría esperar que

dosomethingwith $hashref->{obj} 

para ser igual a

$hashref->{obj}->dosomethingwith(); 

pero en realidad se trata analiza como:

$hashref->dosomethingwith->{obj} 

que probablemente no es lo deseado.

Otro problema es si hay una función en su paquete con el mismo nombre que el método que está tratando de llamar. Por ejemplo, ¿qué pasa si algún módulo que use 'd exportó una función llamada dosomethingwith? En ese caso, dosomethingwith $object es ambiguo y puede dar lugar a errores desconcertantes.

El uso de la sintaxis -> elimina estos problemas exclusivamente, ya que el método y el método sobre el que desea que el método sean siempre claros para el compilador.

21

Ver Indirect Object Syntax en la documentación de perlobj para una explicación de sus peligros. freido's answer cubre uno de ellos (aunque tiendo a evitar eso con parens explícitos alrededor de mis llamadas a funciones).

Larry una vez bromeó diciendo que estaba ahí para hacer que C++ se sintiera feliz por new, y aunque la gente le dirá que nunca lo use, probablemente lo esté haciendo todo el tiempo. Considere esto:

print FH "Some message"; 

¿Alguna vez se ha preguntado si no había una coma después del identificador de archivo? ¿Y no hay una coma después del nombre de la clase en la notación indirecta del objeto? Eso es lo que está pasando aquí. Se podría volver a escribir que a medida que una llamada de método en la impresión:

FH->print("Some message"); 

Es posible que haya experimentado alguna rareza en print si lo haces mal. Poner una coma después del identificador de archivo explícita lo convierte en un argumento:

print FH, "some message";  # GLOB(0xDEADBEEF)some message 

Lamentablemente, tenemos esta goofiness en Perl. No todo lo que entró en la sintaxis fue la mejor idea, pero eso es lo que sucede cuando recurre a tantas fuentes para obtener inspiración. Algunas de las ideas tienen que ser las malas.

+7

No he leído eso página del hombre en años; Realmente debería leer más. Es una lástima 'new Some :: Class' tiene tantas trampas, ya que me gusta la forma en que lee mejor que 'Some :: Class-> new()'; Una de las cosas que más me gusta de Perl es su lenguaje natural. Oh, bueno, es hora de un cambio ..... –

4

La sintaxis del objeto indirecto está mal visto, por buenas razones, pero eso no tiene nada que ver con los constructores. Casi nunca va a tener una función nueva() en el paquete de llamadas. Más bien, se debe utilizar Paquete-> new() para otros dos (mejor?) Razones:

  1. Como usted ha dicho, todos los demás métodos de clase toman la forma Paquete-> método(), por lo que es una buena consistencia Thing

  2. Si está suministrando argumentos al constructor, o está tomando el resultado del constructor y llamando inmediatamente a los métodos (por ejemplo, si no le importa mantener el objeto), es más simple decir, por ejemplo

$foo = Foo->new(type => 'bar', style => 'baz'); 
Bar->new->do_stuff; 

que

$foo = new Foo(type => 'bar', style => 'baz'); 
(new Bar)->do_stuff; 
-3

Otro problema es que new Some::Class sucede en tiempo de ejecución. Si hay un error y la prueba nunca se bifurca a esta afirmación, nunca se sabe hasta que ocurre en producción. Es mejor usar Some::Class->new a menos que esté haciendo una programación dinámica.

Cuestiones relacionadas