2015-10-05 5 views
8

Der Titel fasst es ziemlich zusammen, aber hier ist sowieso die lange Version.Was ist indirekte Objektnotation, warum ist es schlecht und wie vermeidet man es?

Nachdem ich einen kleinen Codeausschnitt geschrieben hatte, wurde mir gesagt, ich solle indirekte Objektnotation vermeiden, "da sie mehrere Nebenwirkungen hat". Der Kommentar diese besondere Zeile verwiesen:

my $some_object = new Some::Module(FIELD => 'value'); 

Wie das ist, wie ich es immer getan habe, in dem Bemühen, mit der Zeit zu bekommen, frage ich deshalb:

  • Was ist damit so schlecht ist? (spezifisch)
  • Was sind die möglichen (vermutlich negativen) Nebenwirkungen?
  • Wie sollte diese Zeile neu geschrieben werden?

Ich wollte den Kommentator fragen, aber für mich ist das seiner eigenen Post wert.

+2

Mein Lieblingsbeispiel für indirekte Objektnotation: [Warum ist dieses Programm gültig? Ich habe versucht, einen Syntaxfehler zu erstellen] (http://stackoverflow.com/q/11695110/176646) – ThisSuitIsBlackNot

+1

Das Hauptproblem mit ION ist es nicht so viel wie die Unterstützung für es in Perl zu verwenden. Das Vorhandensein des Features verursacht mehrere Probleme. Die zwei, an die ich mich gerade erinnern kann: 1) Es verursacht einige Syntaxfehler, die zu sehr merkwürdigen/irreführenden Fehlermeldungen führen. 2) Es verhindert, dass nützliche Funktionen implementiert werden, da sie mit der gültigen ION-Syntax kollidieren. – ikegami

Antwort

17

Das Hauptproblem ist, dass es mehrdeutig ist. Hat

my $some_object = new Some::Module(FIELD => 'value'); 

bedeuten die new Methode in dem Some::Module Paket zu nennen, oder bedeutet es, die new Funktion im aktuellen Paket mit dem Ergebnis, ruft des Aufruf die Module Funktion im Some Paket mit den gegebenen Parametern?

das heißt, es könnte so analysiert werden:

# method call 
my $some_object = Some::Module->new(FIELD => 'value'); 
# or function call 
my $some_object = new(Some::Module(FIELD => 'value')); 

Die Alternative ist Some::Module->new(...) die explizite Methodenaufruf Notation zu verwenden.

Normalerweise wird der Parser richtig geschätzt, aber die beste Vorgehensweise besteht darin, die Mehrdeutigkeit zu vermeiden.

4

Der Kommentator wollte nur Some::Module->new(FIELD => 'value'); als Konstruktor sehen.

Perl kann indirect object syntax for other bare words that look like they might be methods verwenden, aber heute schlägt die perlobj Dokumentation vor, es nicht zu verwenden.

Das allgemeine Problem damit ist, dass auf diese Weise geschriebener Code mehrdeutig ist und Perls Parser ausübt, um den Namespace z. überprüfen Sie, wenn Sie method Namespace schreiben, ob Namespace :: method existiert.

9

Was ist daran so schlimm?

Die Probleme mit indirekter Methode Notation sind vermeidbar, aber es ist viel einfacher, die Leute zu sagen indirekte Methode Notation zu vermeiden.

Das Hauptproblem ist, dass es sehr einfach ist, versehentlich die falsche Funktion aufzurufen.Nehmen Sie den folgenden Code ein, zum Beispiel:

package Widget; 

sub new { ... } 
sub foo { ... } 
sub bar { ... } 

sub method { 
    ...; 
    my $o = new SubWidget; 
    ...; 
} 

1; 

In diesem Code wird new SubWidget erwartet

SubWidget->new() 

Stattdessen bedeuten, bedeutet dies eigentlich

new("SubWidget") 

Das heißt, mit strengen Willen fangen die meisten dieser Instanzen dieses Fehlers. Wurden use strict; dem obigen Schnipsel, der folgende Fehler hinzugefügt werden würde hergestellt werden:

Bareword "SubWidget" not allowed while "strict subs" in use at Widget.pm line 11. 

Das heißt, es gibt Fälle, in denen mit streng den Fehler nicht fangen würde. Sie umfassen hauptsächlich die Verwendung von Parens um die Argumente des Methodenaufrufs (z. B. new SubWidget($x)).

das heißt also

  • Indirekte Object Notation Verwendung ohne parens in ungeraden Fehlermeldungen führen kann.
  • Indirekte Objektnotation mit Parens kann dazu führen, dass der falsche Code aufgerufen wird.

Die erste ist erträglich, und die letztere ist vermeidbar. Aber anstatt den Leuten zu sagen: "Vermeiden Sie Parens um die Argumente von Methodenaufrufen mit Indirekter Methodennotation", sagen wir einfach "Vermeiden Sie die Verwendung der indirekten Methodennotation". Es ist einfach zu zerbrechlich.


Es gibt ein anderes Problem. Es ist nicht nur eine indirekte Objektnotation, sondern ein Problem, das in Perl unterstützt wird. Das Vorhandensein des Features verursacht mehrere Probleme. In erster Linie

  • Es verursacht einige Syntaxfehler, die zu sehr merkwürdigen/irreführenden Fehlermeldungen führen, da der Code ION zu verwenden scheint, wenn dies nicht der Fall war.
  • Es verhindert, dass nützliche Funktionen implementiert werden, da sie mit der gültigen ION-Syntax kollidieren.
  • Auf der positiven Seite hilft die Verwendung von no indirect; das erste Problem.


    Wie sollte diese Zeile neu geschrieben?

    Der richtige Weg, um den Methodenaufruf zu schreiben, ist die folgende:

    my $some_object = Some::Module->new(FIELD => 'value'); 
    

    Das heißt, auch diese Syntax nicht eindeutig ist. Es wird zuerst überprüft, ob eine Funktion mit dem Namen Some::Module existiert. Aber das ist sehr unwahrscheinlich, dass sich nur sehr wenige Menschen vor solchen Problemen schützen.Wenn Sie sich selbst schützen wollten, könnten Sie Folgendes verwenden:

    my $some_object = Some::Module::->new(FIELD => 'value'); 
    
    6

    Darüber, wie es zu vermeiden: Es gibt ein CPAN-Modul, das die Bezeichnung verbietet, benimmt sich wie ein Pragma-Modul:

    no indirect; 
    

    http://metacpan.org/pod/indirect

    +0

    Sein Wert ist begrenzt, weil das Problem in dem Code in meiner Antwort nicht gefunden wird. – ikegami

    Verwandte Themen