2008-11-17 4 views
110

In another Stack Overflow questionLeon Timmermans behauptet:Warum sind die Funktions-Prototypen von Perl 5 schlecht?

ich Sie nicht Prototypen verwenden beraten würde. Sie haben ihren Nutzen, aber nicht in den meisten Fällen und definitiv nicht in diesem.

Warum könnte das wahr sein (oder nicht)? Ich liefere fast immer Prototypen für meine Perl-Funktionen, und ich habe noch nie zuvor gesehen, dass irgendjemand etwas schlechtes gesagt hat.

+0

Ich bin auch neugierig. Die einzige Zeit, die ich sie nicht benutze, ist, wenn ich mit einer variablen Anzahl von Argumenten aufrufe. –

+7

Darf ich Ihnen empfehlen, den Artikel ["Perl Prototypes Considered Harmful"] (http://www.perlmonks.org/?node_id=861966) zu lesen? – tchrist

Antwort

116

Prototypen sind nicht schlecht, wenn sie richtig verwendet werden. Die Schwierigkeit besteht darin, dass Perls Prototypen nicht so funktionieren, wie die Leute es oft erwarten. Menschen mit einem Hintergrund in anderen Programmiersprachen neigen dazu, zu erwarten, dass Prototypen einen Mechanismus zur Überprüfung der Funktionsaufrufe liefern: das heißt, dass sie die richtige Anzahl und Art von Argumenten haben. Die Prototypen von Perl sind für diese Aufgabe nicht geeignet. Es ist die Missbrauch das ist schlecht. Perls Prototypen haben einen einzigartigen und sehr unterschiedlichen Zweck:

Prototypen ermöglichen Ihnen, Funktionen zu definieren, die sich wie integrierte Funktionen verhalten.

  • Klammern sind optional.
  • Kontext wird den Argumenten auferlegt.

Zum Beispiel könnten Sie eine Funktion wie folgt definieren:

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

und nennen es als

mypush @array, 1, 2, 3; 

, ohne dass die \ nehmen einen Verweis auf das Array zu schreiben.

Kurz gesagt, mit Prototypen können Sie Ihren eigenen syntaktischen Zucker herstellen. Zum Beispiel verwendet das Moose-Framework diese, um eine typischere OO-Syntax zu emulieren.

Dies ist sehr nützlich, aber Prototypen sind sehr begrenzt:

  • Sie haben zur Compile-Zeit sichtbar sein.
  • Sie können umgangen werden.
  • Das Weiterleiten von Kontext an Argumente kann zu unerwartetem Verhalten führen.
  • Sie können es schwierig machen, Funktionen aufzurufen, die etwas anderes als das streng vorgeschriebene Formular verwenden.

Siehe Prototypes in Perlsub für alle blutigen Details.

+2

Ich habe diese Antwort akzeptiert, weil ich denke, dass es am besten die Frage beantwortet - Prototypen sind nicht an sich schlecht, es ist nur, wie Sie sie verwenden. – Alnitak

+2

Moose-Prototypen dagegen sind/genial/http://p3rl.org/MooseX::Declare http://p3rl.org/MooseX::Method::Signatures –

+13

[Weit mehr als alles, was Sie jemals wissen wollten Perl-Prototypen] (http://www.perlmonks.org/?node_id=861966). – tchrist

66

Das Problem ist, dass Perls Funktions-Prototypen nicht das tun, was die Leute denken. Ihr Zweck ist es, Ihnen zu ermöglichen, Funktionen zu schreiben, die wie Perls eingebaute Funktionen analysiert werden.

Zunächst ignorieren Methodenaufrufe Prototypen vollständig. Wenn Sie OO-Programmierung machen, ist es egal, welchen Prototyp Ihre Methoden haben. (Sie sollten also keinen Prototyp haben.)

Zweitens werden Prototypen nicht streng durchgesetzt. Wenn Sie ein Unterprogramm mit &function(...) aufrufen, wird der Prototyp ignoriert. Sie bieten also keine Art Sicherheit.

Drittens sind sie gruselige Action-at-distance. (Insbesondere der Prototyp $, der bewirkt, dass der entsprechende Parameter im skalaren Kontext anstelle des standardmäßigen Listenkontexts ausgewertet wird.)

Insbesondere machen sie es schwierig, Parameter von Arrays zu übergeben. Zum Beispiel:

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]); 

druckt:

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

zusammen mit 3 Warnungen über main::foo() called too early to check prototype (wenn Warnungen aktiviert sind). Das Problem besteht darin, dass ein Array (oder Array-Slice), das im skalaren Kontext ausgewertet wird, die Länge des Arrays zurückgibt.

Wenn Sie eine Funktion schreiben müssen, die sich wie eine integrierte Funktion verhält, verwenden Sie einen Prototyp. Andernfalls verwenden Sie keine Prototypen.

Hinweis: Perl 6 wird komplett überarbeitete und sehr nützliche Prototypen haben. Diese Antwort gilt nur für Perl 5.

+0

Aber sie bieten immer noch eine nützliche Überprüfung, dass Ihr Anrufer und das Sub die gleiche Anzahl von Argumenten verwenden, also was ist los damit? –

+0

das ist der Punkt meiner Frage - ich benutze nie die alte & func-Syntax, so dass der Prototyp nützliche Funktion Parameterprüfung bietet. – Alnitak

+2

Nein; Der allgemeine Konsens besteht darin, dass Perl-Funktionsprototypen im Wesentlichen keinen Nutzen bringen. Sie können sich zumindest in Perl 5 auch nicht damit beschäftigen. Perl 6 könnte eine andere (bessere) Geschichte sein. –

29

Ich stimme den obigen zwei Plakaten zu. Im Allgemeinen sollte die Verwendung von $ vermieden werden. Prototypen sind nur dann sinnvoll, wenn der Block Argumenten (&), Klümpchen (*) oder Referenz Prototypen (\@, \$, \%, \*)

+0

Im Allgemeinen vielleicht, aber ich möchte zwei Ausnahmen erwähnen: Erstens, der '($)' -Prototyp erstellt einen benannten unären Operator, der nützlich sein kann (sicherlich findet Perl sie nützlich; ich habe es auch gelegentlich). Zweitens sollten Sie beim Überschreiben von Einfügungen (ob durch Importieren oder Verwenden von CORE :: GLOBAL: :) im Allgemeinen an jedem Prototyp festhalten, den die integrierte Klasse hatte, selbst wenn dies ein '$' enthält, oder Sie könnten den Programmierer überraschen (Sie selbst, gerade) mit Listenkontext, wo der eingebaute Skalarkontext sonst zur Verfügung stünde. –

1

Einige Leute an einem Perlfunktionen Prototyp suchen, denkt bedeutet es etwas, das es doesn 't:

sub some_sub ($$) { ... } 

Zu Perl bedeutet das, dass der Parser zwei Argumente erwartet. Auf diese Weise können Sie Subroutinen erstellen, die sich wie integrierte Funktionen verhalten, die alle wissen, was Sie von dem nachfolgenden Code erwarten können. Sie können über Prototypen in perlsub

lesen Ohne die Dokumentation zu lesen, raten die Leute, dass die Prototypen auf Laufzeit-Argumentprüfung oder etwas Ähnliches verweisen, das sie in anderen Sprachen gesehen haben. Wie bei den meisten Dingen, die Leute über Perl erraten, entpuppen sie sich als falsch.

Allerdings hat Perl, beginnend mit Perl v5.20, eine Funktion, experimentell, wie ich dies schreibe, die etwas mehr gibt, was die Benutzer erwarten und was. Perl subroutine signatures ist Zeitargument Zählen laufen, Variablen zugewiesen, und Standardeinstellung:

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"; 
    } 

Dies ist die Funktion, die Sie wahrscheinlich wollen, wenn Sie Prototypen erwägen.

Verwandte Themen