Perché alcuni utenti citano i nomi delle classi in Perl?


12

Guardando Type::Tiny, vedo che il nome della classe nella chiamata a Type::Tiny->newè citato nei documenti ufficiali,

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

Perchè è questo? Questo è solo stile? Ci sono conseguenze sulle prestazioni per questa pratica?

Risposte:


7

Prendi un esempio più semplice

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

Nell'esempio sopra, la costante si Foorisolve in "Bar", quindi "Bar"->newnon chiama "Foo"->new. Come si interrompe la risoluzione della subroutine? Puoi citarlo.

"Foo"->new();

Per quanto riguarda le implicazioni sulle prestazioni, le cose non peggiorano usando una stringa piuttosto che una parola nuda. Ho confermato che l'optree generato da O=Deparseè lo stesso. Quindi, come regola generale, sembra che sia meglio citare i Classname se si valuta la correttezza.

Questo è menzionato nella Programmazione del Perl (purtroppo nel contesto dell'invocazione indiretta del metodo )

... quindi ti diremo che puoi quasi sempre cavartela con un nome di classe nudo, a condizione che due cose siano vere. Innanzitutto, non esiste una subroutine con lo stesso nome della classe. (Se segui la convenzione che nomi di subroutine come newstart minuscolo e nomi di classe come ElvenRingstart maiuscolo , questo non è mai un problema). In secondo luogo, la classe è stata caricata con uno di

use ElvenRing;
require ElvenRing;

Entrambe queste dichiarazioni assicurano che Perl sappia che ElvenRingè un nome di modulo, che forza qualsiasi nome nudo come newprima del nome della classe ElvenRingad essere interpretato come una chiamata di metodo, anche se ti capita di aver dichiarato una newtua subroutine nel pacchetto corrente.

E questo ha senso: la confusione qui può verificarsi solo se le tue subroutine (in genere minuscole) hanno lo stesso nome di una classe (in genere maiuscole). Questo può succedere solo se si viola quella convenzione di denominazione sopra.

TLDR; è probabilmente una buona idea citare i tuoi nomi di classe, se li conosci e apprezzi la correttezza rispetto al disordine.

Nota a margine: in alternativa è possibile interrompere la risoluzione di un bareword a una funzione fissando ::a alla fine di esso, ad esempio in precedenza Foo::->new.


Grazie a Ginnz su reddit per avermelo segnalato e a Toby Inkster per il commento (anche se non aveva senso per me in prima lettura).


2
Oppure Foo::->new, come ho imparato da Ikegami.
mafia il

@mob sì, il libro Perl menziona anche questo (esplicitamente), non sono sicuro se dovrei metterlo lì o no? lol.
Evan Carroll,

@mob L'ho aggiunto anche io, come nota a piè di pagina. Anche se non sono sicuro che mi piaccia.
Evan Carroll,

1
Foo::ha il vantaggio che avverte se Foonon è un pacchetto esistente
ikegami il

1
Prova :: Tiny è un esempio migliore di Foo. Nel tuo codice usando Foo->puoi aspettarti di sapere che non esiste una subroutine nel tuo pacchetto. Ma se stai usando Try :: Tiny e un certo numero di altri moduli cpan / altri di provenienza esterna, chi può dire se uno di loro sta usando un pacchetto Try, e se è così, se c'è un sub piccolo in esso?
ysth

0

Citare esplicitamente il nome della classe piuttosto che usare una parola nuda (che viene trattata come una stringa) è uno dei tre modi per evitare l'ambiguità sintattica. La sezione Metodi di classe invocanti della documentazione di perlobj spiega.

Poiché Perl consente di utilizzare le password per i nomi dei pacchetti e dei sottoprogrammi, a volte interpreta il significato di una parola non corretta. Ad esempio, il costrutto Class->new()può essere interpretato come uno 'Class'->new()o Class()->new(). In inglese, quella seconda interpretazione si legge come "chiama una subroutine denominata Class(), quindi chiama new()come metodo sul valore restituito di Class()". Se esiste una subroutine denominata Class()nello spazio dei nomi corrente, Perl interpreterà sempre Class->new()come la seconda alternativa: una chiamata a new()sull'oggetto restituita da una chiamata a Class().

Guarda questo strano caso in azione con la demo di seguito.

#! /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;

Il suo output è

Ritorno fasullo
Bogus :: new
Tipo :: :: Piccolo nuova
Tipo :: :: Piccolo nuova
Tipo :: :: Piccolo nuova

Il resto della sezione di documentazione sopra menzionata mostra come proteggere da comportamenti sorprendenti o errori involontari.

È possibile forzare Perl a utilizzare la prima interpretazione ( ovvero , come una chiamata di metodo sulla classe denominata "Class") in due modi. Innanzitutto, puoi aggiungere ::a al nome della classe:

Class::->new()

Perl interpreterà sempre questo come una chiamata di metodo.

In alternativa, puoi citare il nome della classe:

'Class'->new()

Naturalmente, se il nome della classe è in uno scalare, Perl farà anche la cosa giusta:

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

Applicando alla tua domanda, tutte le chiamate sotto sono equivalenti.

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

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

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

L'aggiunta ::alla fine ha il vantaggio di produrre un avviso utile. Di 'che hai digitato per errore

Type::Tinny::->new;

Questo produce

La parola nuda "Tipo :: Tinny ::" si riferisce al pacchetto inesistente alla riga ./try 15.
Impossibile trovare il metodo oggetto "nuovo" tramite il pacchetto "Tipo :: Tinny" (forse hai dimenticato di caricare "Tipo :: Tinny"?) Alla riga ./try 15.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.