2008-11-17 18 views
110

In another Stack Overflow questionLeon Timmermans affermato:Perché i prototipi di funzione di Perl 5 sono danneggiati?

Vi consiglio di non usare prototipi. Hanno i loro usi, ma non nella maggior parte dei casi e sicuramente non in questo.

Perché questo potrebbe essere vero (o altrimenti)? Quasi sempre fornisco i prototipi per le mie funzioni Perl, e non ho mai visto nessuno dire nulla di male nell'utilizzarli.

+0

Anch'io sono curioso. L'unica volta che non li uso è quando sto chiamando con un numero variabile di argomenti. –

+7

Posso raccomandare di leggere l'articolo, ["Perl Prototypes Considerated Harmful"] (http://www.perlmonks.org/?node_id=861966)? – tchrist

risposta

116

I prototipi non sono male se usati correttamente. La difficoltà è che i prototipi di Perl non funzionano nel modo in cui spesso le persone si aspettano che lo facciano. Le persone con uno sfondo in altri linguaggi di programmazione tendono ad aspettarsi che i prototipi forniscano un meccanismo per verificare che le chiamate di funzione siano corrette: cioè, che abbiano il numero e il tipo di argomenti giusti. I prototipi di Perl non sono adatti per questo compito. È il uso improprio che è male. I prototipi di Perl hanno uno scopo singolare e molto diverso:

I prototipi consentono di definire funzioni che si comportano come funzioni integrate.

  • Le parentesi sono facoltative.
  • Il contesto è imposto sugli argomenti.

Ad esempio, è possibile definire una funzione come questa:

sub mypush(\@@) { ... } 

e chiamare come

mypush @array, 1, 2, 3; 

senza bisogno di scrivere il \ prendere un riferimento alla matrice.

In breve, i prototipi consentono di creare il proprio zucchero sintattico. Ad esempio, il framework Moose li usa per emulare una sintassi OO più tipica.

Questo è molto utile, ma prototipi sono molto limitate:

  • Devono essere visibili al momento della compilazione.
  • Possono essere bypassati.
  • La propagazione del contesto agli argomenti può causare un comportamento imprevisto.
  • Possono rendere difficile chiamare le funzioni utilizzando qualsiasi altra cosa che non sia il modulo rigorosamente prescritto .

Vedere Prototypes in perlsub per tutti i dettagli sanguinosi.

+2

Ho accettato questa risposta perché ritengo che risponda meglio alla domanda - i prototipi non sono intrinsecamente cattivi, è solo il modo in cui li usi. – Alnitak

+2

I prototipi di alci, d'altra parte, sono/fantastico/http://p3rl.org/MooseX::Declare http://p3rl.org/MooseX::Method::Messaggi –

+13

[Molto più di tutto ciò che avresti sempre voluto sapere su Prototipi Perl] (http://www.perlmonks.org/?node_id=861966). – tchrist

66

Il problema è che i prototipi di funzione di Perl non fanno ciò che le persone pensano di fare. Il loro scopo è quello di consentire di scrivere funzioni che verranno analizzate come le funzioni built-in di Perl.

Prima di tutto, le chiamate di metodo ignorano completamente i prototipi. Se stai programmando OO, non importa quale prototipo hanno i tuoi metodi. (Quindi non dovrebbero avere alcun prototipo.)

Secondo, i prototipi non sono rigorosamente applicati. Se si chiama una subroutine con &function(...), il prototipo viene ignorato. Quindi non forniscono alcun tipo di sicurezza.

In terzo luogo, sono un'azione spettrale a distanza. (Soprattutto il prototipo $, che causa la valutazione del parametro corrispondente in contesto scalare, invece del contesto elenco predefinito.)

In particolare, rendono difficile passare i parametri dagli array. Per esempio:

my @array = qw(a b c); 

foo(@array); 
foo(@array[0..1]); 
foo($array[0], $array[1], $array[2]); 

sub foo ($;$$) { print "@_\n" } 

foo(@array); 
foo(@array[0..1]); 
foo($array[0], $array[1], $array[2]); 

stampe:

a b c 
a b 
a b c 
3 
b 
a b c 

insieme a 3 avvertimenti circa main::foo() called too early to check prototype (se gli avvertimenti sono attivati). Il problema è che una matrice (o una sezione di matrice) valutata in contesto scalare restituisce la lunghezza della matrice.

Se è necessario scrivere una funzione che funzioni come un built-in, utilizzare un prototipo. Altrimenti, non usare prototipi.

Nota: Perl 6 avrà prototipi completamente rinnovati e molto utili. Questa risposta vale solo per Perl 5.

+0

Ma forniscono ancora un utile controllo che il tuo chiamante e il sub stiano usando lo stesso numero di argomenti, quindi cosa c'è di sbagliato in questo? –

+0

è il punto della mia domanda: non uso mai la sintassi old & func, quindi il prototipo fornisce un utile controllo dei parametri di funzione. – Alnitak

+2

No; il consenso generale è che i prototipi di funzione Perl non offrono sostanzialmente alcun beneficio. Puoi anche non preoccuparti di loro, almeno in Perl 5. Perl 6 potrebbe essere una storia diversa (migliore). –

29

Sono d'accordo con i due poster precedenti. In generale, si dovrebbe evitare l'uso di $. I prototipi sono utili solo quando si utilizza argomenti di blocco (&), gocce (*), o prototipi di riferimento (\@, \$, \%, \*)

+0

In generale, forse, ma vorrei menzionare due eccezioni: in primo luogo, il prototipo '($)' crea un operatore unario chiamato, che può essere utile (sicuramente Perl li trova utili, anche io a volte). In secondo luogo, quando si esegue l'override dei built-in (sia tramite l'importazione che l'utilizzo di CORE :: GLOBAL: :), in generale dovresti attenersi a qualsiasi prototipo del built-in, anche se questo include un '$', o potresti sorprendere il programmatore (te stesso, anche) con un contesto di lista in cui il built-in fornirebbe altrimenti un contesto scalare. –

1

Alcune persone, guardando una subroutine prototipo di Perl, pensa che significhi qualcosa che doesn 't:

sub some_sub ($$) { ... } 

In Perl, ciò significa che il parser prevede due argomenti. È il modo in cui Perl ti permette di creare subroutine che si comportano come built-in, tutte cose che sanno cosa aspettarsi dal codice successivo. È possibile leggere i prototipi in perlsub

Senza leggere la documentazione, le persone ritengono che i prototipi si riferiscano al controllo degli argomenti di runtime o qualcosa di simile che hanno visto in altre lingue. Come con la maggior parte delle cose che la gente indovina di Perl, si rivelano sbagliate.

Tuttavia, a partire da Perl v5.20, Perl ha una funzione, sperimentale mentre scrivo questo, che dà qualcosa di più simile a ciò che gli utenti si aspettano e che cosa. Perl subroutine signatures viene eseguito il conteggio tempo argomento, l'assegnazione di variabili, e l'impostazione di default:

use v5.20; 
use feature qw(signatures); 
no warnings qw(experimental::signatures); 

animals('Buster', 'Nikki', 'Godzilla'); 

sub animals ($cat, $dog, $lizard = 'Default reptile') { 
    say "The cat is $cat"; 
    say "The dog is $dog"; 
    say "The lizard is $lizard"; 
    } 

Questa è la funzione che si desidera probabilmente se state pensando di prototipi.

Problemi correlati