Warum zitieren einige Benutzer Klassennamen in Perl?

12

Wenn Type::Tinyich mir Type::Tiny->newdas ansehe, sehe ich, dass der Klassenname im Aufruf von in den offiziellen Dokumenten zitiert wird.

my $NUM = "Type::Tiny"->new(
   name       => "Number",
   constraint => sub { looks_like_number($_) },
   message    => sub { "$_ ain't a number" },
);

Warum ist das? Ist das nur Stil? Gibt es Leistungsauswirkungen für diese Praxis?

Evan Carroll
quelle

Antworten:

7

Nehmen Sie ein einfacheres Beispiel

package Foo { sub new { die 7  } };
package Bar { sub new { die 42 } };
sub Foo { "Bar" }
Foo->new();

Im obigen Beispiel wird die Konstante Fooin "Bar" aufgelöst, sodass dies "Bar"->newnicht aufgerufen wird "Foo"->new. Wie verhindern Sie die Auflösung des Unterprogramms? Sie können es zitieren.

"Foo"->new();

Was die Auswirkungen auf die Leistung betrifft, werden die Dinge nicht durch die Verwendung einer Zeichenfolge anstelle eines Barworts verschlimmert. Ich habe bestätigt, dass das von erzeugte Optree O=Deparsedasselbe ist. In der Regel ist es daher besser, die Klassennamen zu zitieren, wenn Sie Wert auf Korrektheit legen.

Dies wird in Programming Perl erwähnt (leider im Zusammenhang mit dem indirekten Methodenaufruf ).

... also werden wir Ihnen sagen, dass Sie fast immer mit einem bloßen Klassennamen davonkommen können, vorausgesetzt, zwei Dinge sind wahr. Erstens gibt es keine Unterroutine mit demselben Namen wie die Klasse. (Wenn Sie der Konvention folgen, dass Unterprogrammnamen wie newStart Kleinbuchstaben und Klassennamen wie ElvenRingStart Großbuchstaben , ist dies nie ein Problem). Zweitens wurde die Klasse mit einem von geladen

use ElvenRing;
require ElvenRing;

Jede dieser Deklarationen stellt sicher, dass Perl weiß, dass ElvenRinges sich um einen Modulnamen handelt, der erzwingt, dass jeder bloße Name wie newvor dem Klassennamen ElvenRingals Methodenaufruf interpretiert wird, selbst wenn Sie newim aktuellen Paket zufällig eine eigene Unterroutine deklariert haben .

Und das macht Sinn: Die Verwirrung hier kann nur auftreten, wenn Ihre Unterprogramme (normalerweise Kleinbuchstaben) denselben Namen wie eine Klasse haben (normalerweise Großbuchstaben). Dies kann nur passieren, wenn Sie gegen die oben genannte Namenskonvention verstoßen.

tldr; Es ist wahrscheinlich eine gute Idee, Ihre Klassennamen zu zitieren, wenn Sie sie kennen und Wert auf Korrektheit legen.

Randnotiz: Alternativ können Sie die Auflösung eines Barworts zu einer Funktion stoppen, indem Sie ein ::am Ende befestigen , z. B. oben Foo::->new.


Vielen Dank an Ginnz auf reddit, der mich darauf hingewiesen hat , und an Toby Inkster für den Kommentar (obwohl es für mich beim ersten Lesen keinen Sinn ergab).

Evan Carroll
quelle
2
Oder Foo::->newwie ich von Ikegami gelernt habe.
Mob
@mob ja, das Perl-Buch erwähnt das auch (explizit), nicht sicher, ob ich das dort ablegen soll oder nicht? lol.
Evan Carroll
@mob Das habe ich auch als Fußnote hinzugefügt. Obwohl ich nicht sicher bin, ob es mir gefällt.
Evan Carroll
1
Foo::hat den Vorteil, dass es warnt, wenn Fooes kein vorhandenes Paket gibt
ikegami
1
Try :: Tiny ist ein besseres Beispiel als Foo. Es Foo->ist zu erwarten, dass Sie in Ihrem Code mit wissen, dass Ihr Paket keine solche Unterroutine enthält. Aber wenn Sie Try :: Tiny und eine Reihe anderer cpan / anderer externer Module verwenden, wer sagt dann, ob eines von ihnen ein Try-Paket verwendet, und wenn ja, ob es ein Tiny-Sub enthält?
Ysth
0

Das explizite Zitieren des Klassennamens anstelle eines Barworts (das als Zeichenfolge behandelt wird) ist eine von drei Möglichkeiten, um syntaktische Mehrdeutigkeiten zu vermeiden. Der Abschnitt Aufrufen von Klassenmethoden in der perlobj-Dokumentation wird erläutert.

Da Sie mit Perl Barwörter für Paketnamen und Unterprogrammnamen verwenden können, wird die Bedeutung eines Barworts manchmal falsch interpretiert. Beispielsweise kann das Konstrukt Class->new()entweder als 'Class'->new()oder als interpretiert werden. Class()->new()In Englisch lautet diese zweite Interpretation "Aufruf einer Unterroutine mit dem Namen Class()und Aufruf new()als Methode für den Rückgabewert von Class()". Wenn Class()im aktuellen Namespace eine Unterroutine benannt ist , wird Perl immer Class->new()als zweite Alternative interpretiert : ein Aufruf von new()für das Objekt, das von einem Aufruf von zurückgegeben wird Class().

Sehen Sie diesen seltsamen Fall in Aktion mit der folgenden Demo.

#! /usr/bin/env perl

use strict;
use warnings;

sub Type::Tiny { print "Returning Bogus\n" ; return "Bogus" }

sub Type::Tiny::new { print "Type::Tiny::new\n" }

sub Bogus::new { print "Bogus::new\n" }

my $class = "Type::Tiny";

Type::Tiny->new;
Type::Tiny::->new;
"Type::Tiny"->new;
$class->new;

Seine Ausgabe ist

Bogus zurückgeben
Schwindel :: neu
Geben Sie :: Tiny :: new ein
Geben Sie :: Tiny :: new ein
Geben Sie :: Tiny :: new ein

Der Rest der oben genannten Dokumentation zeigt, wie Sie sich vor überraschendem Verhalten oder versehentlichen Fehlern schützen können.

Sie können Perl zwingen, die erste Interpretation ( dh als Methodenaufruf für die genannte Klasse "Class") auf zwei Arten zu verwenden. Zunächst können Sie a ::an den Klassennamen anhängen :

Class::->new()

Perl interpretiert dies immer als Methodenaufruf.

Alternativ können Sie den Klassennamen angeben:

'Class'->new()

Wenn sich der Klassenname in einem skalaren Perl befindet, wird Perl natürlich auch das Richtige tun:

my $class = 'Class';
$class->new();

Bei Beantwortung Ihrer Frage sind alle folgenden Anrufe gleichwertig.

Type::Tiny::->new(  );

"Type::Tiny"->new(  );

my $class = "Type::Tiny";
$class->new(  );

Das Anhängen ::an das Ende hat den Vorteil, dass eine hilfreiche Warnung ausgegeben wird. Angenommen, Sie haben versehentlich getippt

Type::Tinny::->new;

Das produziert

Das Barwort "Type :: Tinny ::" bezieht sich auf ein nicht vorhandenes Paket in ./try Zeile 15.
Sie können die Objektmethode "new" nicht über das Paket "Type :: Tinny" (möglicherweise haben Sie vergessen, "Type :: Tinny" zu laden?) In Zeile ./try finden.
Greg Bacon
quelle