2009-01-09 6 views
27

vielen Jahren erinnere ich mich an einen Kerl Programmierer Beratung dies:Was ist der Unterschied zwischen der neuen Some :: Class und Some :: Class-> new() in Perl? Vor

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

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

Leider kann ich jetzt nicht den/seinen Grund mehr, warum. :(Beide Formulare funktionieren korrekt, auch wenn der Konstruktor nicht tatsächlich im Some :: Class-Modul existiert, sondern von einem Elternteil irgendwo geerbt wird.

Keine dieser Formen sind identisch mit Some :: Class :: new(), die den Namen der Klasse nicht als ersten Parameter an den Konstruktor übergibt - daher ist dieses Formular immer falsch

Auch wenn die beiden Formulare gleichwertig sind, finde ich Some :: Class-> new () um viel klarer zu sein, da es der Standardkonvention für den Aufruf einer Methode auf einem Modul folgt, und in Perl die 'neue' Methode nicht speziell ist - ein Konstruktor könnte irgendwas heißen, und new() könnte alles tun (obwohl Natürlich erwarten wir, dass es sich um einen Konstrukteur handelt.)

+0

Eine weitere ausgezeichnete Referenz: [Indirekt aber immer noch tödlich] (http://www.shadowcat.co.uk/blog/matt-s-trout/indirect-but-still-fatal/) – Ether

Antwort

26

Die Verwendung von new Some::Class wird "indirekter" Methodenaufruf genannt, und es ist schlecht, weil es einige Mehrdeutigkeiten in die Syntax einführt.

Ein Grund, warum es fehlschlagen kann, ist, wenn Sie ein Array oder Hash von Objekten haben. Man könnte erwarten,

dosomethingwith $hashref->{obj} 

gleich

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

zu

sein, aber es parst tatsächlich als:

$hashref->dosomethingwith->{obj} 

was wahrscheinlich ist, nicht das, was Sie wollten.

Ein anderes Problem ist, wenn in Ihrem Paket eine Funktion mit demselben Namen wie eine Methode, die Sie aufrufen möchten, vorhanden ist. Zum Beispiel, was, wenn ein Modul, das Sie use eine Funktion namens dosomethingwith exportiert haben? In diesem Fall ist dosomethingwith $object mehrdeutig und kann zu rätselhaften Fehlern führen.

Die Verwendung der ->-Syntax beseitigt ausschließlich diese Probleme, da die Methode und die Methode, auf der die Methode ausgeführt werden soll, dem Compiler immer klar ist.

21

Siehe Indirect Object Syntax in der perlobj Dokumentation für eine Erklärung seiner Fallstricke. freido's answer deckt einen von ihnen ab (obwohl ich dazu tendiere, das mit expliziten Parens um meine Funktionsaufrufe zu vermeiden).

Larry hat einmal gescherzt, dass es da war, um das C++ über new glücklich zu machen, und obwohl die Leute dir sagen werden, dass du es nie benutzen wirst, machst du es wahrscheinlich die ganze Zeit. Betrachten Sie das:

Haben Sie sich jemals gefragt, meine gab es kein Komma nach dem Dateihandle? Und es gibt kein Komma nach dem Klassennamen in der indirekten Objektnotation? Das ist hier passiert. Man könnte das als Methodenaufruf auf Druck umschreiben:

FH->print("Some message"); 

Sie erfahren in print etwas Verrücktheit haben kann, wenn man es falsch macht. Setzen Sie ein Komma nach dem expliziten Datei-Handle verwandelt es sich in ein Argument:

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

Leider haben wir diese goofiness in Perl. Nicht alles, was in die Syntax hineingeraten ist, ist die beste Idee, aber das passiert, wenn man aus so vielen Quellen zur Inspiration greift. Einige der Ideen müssen die schlechten sein.

+7

Ich habe das nicht gelesen Man Seite in Jahren; Ich sollte wirklich mehr davon lesen. Es ist eine Schande, dass 'neue Some :: Class' so viele Fallstricke hat, wie ich es besser finde als 'Some :: Class-> new()'; Eines der Dinge, die ich am meisten an Perl mag, ist das natürliche Sprachgefühl. Naja, Zeit für einen Wechsel ..... –

4

Die indirekte Objekt-Syntax ist aus guten Gründen verpönt, aber das hat nichts mit Konstruktoren zu tun. Sie werden fast nie eine neue() Funktion im aufrufenden Paket haben. Vielmehr sollten Sie Package- verwenden> new() für zwei andere (bessere?) Gründe:

  1. Wie Sie sagten, alle anderen Klassenmethoden die Form Package- nehmen> Methode(), so Konsistenz ist ein gutes Thing

  2. Wenn Sie Argumente an den Konstruktor übergeben oder wenn Sie das Ergebnis des Konstruktors verwenden und Methoden sofort aufrufen (wenn Sie beispielsweise das Objekt nicht herumführen möchten), ist es einfacher sag zB

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

als

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

Ein weiteres Problem besteht darin, dass new Some::Class zur Laufzeit geschieht. Wenn es einen Fehler gibt und Sie Tests nie zu dieser Aussage verzweigen, wissen Sie es nie, bis es in der Produktion passiert. Es ist besser, Some::Class->new zu verwenden, es sei denn, Sie machen dynamische Programmierung.