2009-01-09 9 views
27

Il y a plusieurs années, je me souviens d'un collègue programmeur conseiller ceci:Quelle est la différence entre new Some :: Class et Some :: Class-> new() dans Perl?

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

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

Malheureusement maintenant je ne me souviens pas de la/sa raison. :(Les ​​deux formes fonctionneront correctement même si le constructeur n'existe pas réellement dans le module Some :: Class mais est hérité d'un parent quelque part

Aucune de ces formes ne ressemble à Some :: Class :: new(), qui ne passera pas le nom de la classe comme premier paramètre au constructeur - donc cette forme est toujours incorrecte

Même si les deux formes sont équivalentes, je trouve Some :: Class-> new () pour être beaucoup plus clair, car il suit la convention standard pour appeler une méthode sur un module, et en perl, la méthode 'new' n'est pas spéciale - un constructeur pourrait s'appeler n'importe quoi, et new() pourrait faire n'importe quoi (bien que bien sûr, nous nous attendons généralement à ce qu'il soit un constructeur.)

+0

Une autre excellente référence: [Indirect mais toujours fatale] (http://www.shadowcat.co.uk/blog/matt-s-trout/indirect-but-still-fatal/) – Ether

Répondre

26

L'utilisation de new Some::Class est appelée invocation de méthode "indirecte", et elle est mauvaise car elle introduit une certaine ambiguïté dans la syntaxe.

L'une des raisons de l'échec est si vous avez un tableau ou un hachage d'objets. Vous pourriez vous attendre

dosomethingwith $hashref->{obj} 

égale à

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

mais il fait comme Parsis:

$hashref->dosomethingwith->{obj} 

qui est probablement pas ce que vous vouliez.

Un autre problème est s'il existe une fonction dans votre package avec le même nom qu'une méthode que vous essayez d'appeler. Par exemple, que se passe-t-il si un module que vous use 'a exporté une fonction appelée dosomethingwith? Dans ce cas, dosomethingwith $object est ambigu et peut entraîner des bogues déconcertants.L'utilisation de la syntaxe -> élimine exclusivement ces problèmes car la méthode et la méthode sur laquelle vous voulez que la méthode fonctionne sont toujours claires pour le compilateur.

21

Voir Indirect Object Syntax dans la documentation perlobj pour une explication de ses pièges. freido's answer couvre l'un d'entre eux (bien que j'ai tendance à éviter cela avec des parens explicite autour de mes appels de fonction). Larry a dit en plaisantant qu'il était là pour que le C++ soit satisfait de new, et bien que les gens vous disent de ne jamais l'utiliser, vous le faites probablement tout le temps. Considérez ceci:

print FH "Some message"; 

Avez-vous déjà demandé s'il n'y avait pas de virgule après le fichier? Et il n'y a pas de virgule après le nom de classe dans la notation d'objet indirect? C'est ce qui se passe ici. Vous pouvez réécrire que comme un appel de méthode sur l'impression:

FH->print("Some message"); 

Vous avez sans doute connu quelques bizarreries dans print si vous le faites mal. Mettre une virgule après le descripteur de fichier explicite, il se transforme en un argument:

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

Malheureusement, nous avons ce goofiness en Perl. Ce n'était pas la meilleure idée, mais c'est ce qui arrive quand on tire de nombreuses sources d'inspiration. Certaines des idées doivent être les mauvaises.

+7

Je n'ai pas lu ça page de man en années; Je devrais vraiment en lire plus. Il est dommage que 'new Some :: Class' ait autant d'embûches, car j'aime mieux la façon dont elle se lit que 'Some :: Class-> new()'; L'une des choses que j'aime le plus chez Perl, c'est la sensation de langage naturel. Eh bien, il est temps de changer ... –

4

La syntaxe d'objet indirect est mal vue, pour de bonnes raisons, mais cela n'a rien à voir avec les constructeurs. Vous n'allez presque jamais avoir une nouvelle fonction() dans le paquet appelant. Au contraire, vous devez utiliser Package-> nouveau() pour deux autres (mieux?) Raisons:

  1. Comme vous l'avez dit, toutes les autres méthodes de classe prennent la forme Package-> méthode(), si la cohérence est une bonne

  2. Si vous fournissez des arguments au constructeur, ou si vous prenez le résultat du constructeur et appelez immédiatement des méthodes (si par exemple vous ne vous souciez pas de garder l'objet), il est plus simple de dire par exemple

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

que

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

Un autre problème est que new Some::Class arrive au moment de l'exécution. S'il y a une erreur et que vous testez jamais les branchements à cette instruction, vous ne la connaissez jamais jusqu'à ce qu'elle se produise en production. Il est préférable d'utiliser Some::Class->new sauf si vous effectuez une programmation dynamique.

Questions connexes