Nur vorab: ich bin nicht gegen Perl, sondern eigentlich dafür 🙂
Punkt eins: You see, „prototypes“ were really a bug fix. (Quelle: http://library.n0i.net/programming/perl/articles/fm_prototypes: Far More Than Everything You’ve Ever Wanted to Know about Prototypes in Perl die Quelle wurde leider entfernt) Das ist schon mal irgendwie nicht so toll.
Punkt zwei: ich habe versucht die bless() Funktion zu dekorieren und musste mit erschrecken feststellen, dass deren Prototyp mal wieder voller (Schwarz-)Magie steckt. Definieren kann man folgendes in einem Prototyp:
- Der „Rest“ der Parameter. Schnappt sich ALLE Parameter und fügt sie ganz normal an @_ an, Macht nur am Ende eines Prototyps Sinn. Eine normale Funktion kann also ohne Prototyp oder mit sub test(@) {} geschrieben werden. Das macht keinen Unterschied.
- Gleichbedeutend mit @
- Ein Array, und zwar wirklich eine Variable die mit @ beginnt, wie z.B. @test. Listen sind nicht erlaubt. (1,2,3) geht nicht! %test, was intern ja auch nur eine Liste ist, auch nicht. In @_ wird eine Referenz auf das Array als einzelner Parameter eingefügt.
- Ein Array, und zwar wirklich eine Variable die mit % beginnt, wie z.B. %test. Listen sind nicht erlaubt. (a => 1, b => 2, c => 3) geht nicht! In @_ wird eine Referenz auf den Hash als einzelner Parameter eingefügt.
- Ein Scalar. Steht an der Stelle ein Array, ein Hash oder eine Liste, wird in @_ nur die Anzahl der Elemente eingefügt. Ansonsten der Wert des Parameters. Es ist im Grunde so, als würde man um seinen Parameter ein scalar() schreiben
- Eine Scalar, KEIN reiner Text! Es MUSS eine Variable sein die mit $ beginnt. In @_ wird eine Referenz auf den Scalar eingefügt
- Ein Glob, und NUR ein solcher. Nicht etwa „irgendeine Variable“. In @_ wird eine Referenz auf den Glob eingefügt
- Ein Glob ODER alles andere. Bei einem Glob wird in @_ wird eine Referenz auf den Glob eingefügt. Bei einem Array oder einer Liste, die hier mal funktioniert, verhält es sich wie $. Bei einer Subroutine verhält es sich wie & (bzw auch $ macht da das gleiche).
- Eine Funktionsreferenz oder ein Block. Wenn per sub {…} die Funktion als Referenz übergeben wird, wird die Referenz einfach in @_ gehängt. Wird das sub weggelassen, also nur ein Block übergeben, wirds ganz verrückt. Dann MUSS beim Funktionsaufruf
die Klammer weggelassen werden,das Komma nach dem Block weggelassen werden und es MUSS der erste Parameter sein. grep und sort sind z.B. so Kandidaten, die das verwenden. - Gleichbedeutend mit &
- Trennt Pflich- von den optionalen Parametern
Bei bless() ist es nun so, dass der Prototyp eigentlich bless(\@;\@) ist, aber eben auch wieder nicht. Denn in dem speziellen Fall erlaubt das \@ auch Listen. Das Führt zwar am Ende zu einem Laufzeitfehler, funktioniert aber erst mal.
Und auch fraglich ist die Tatsache, dass der zweite Parameter von bless() ebenfalls eine Liste sein kann. Das letzte Element ist dann die „Klasse“, mit der geblesst wird. Aber was ist mit dem Rest? Ist das einfach ein Fehler oder passiert damit im Hintergrund irgendwas … ganz tolles?!?
Und das wichtigste: schlafe ich vieleicht einfach besser, wenn ich in dem Punkt unwissend bleibe?
Punkt 3, nur der vollständigkeit halber: Prototypen greifen nur, wenn man die Funktion direkt und ohne & benutzt. Indirekt, per OO also, oder per &$sub_ref() oder ähnliches geht nicht. Prototypen sind also NUR für global verfügbare Funktionen, oder Funktionen der eigenen Klasse sinnvoll (oder auch nicht).
PS: auch noch schon und auch aus obiger Quelle Since you gave Perl a ridiculous request, Perl dutifully provides you in return a ridiculous response – but not an error; oh no, not that!
Nachtrag: bless() hat den Prototyp (\@;$), nur verhält sich $ anders als gedacht. Steht dort eine Liste, wird das letzte Element verwendet. Ist es ein @Array, dann wird die länge ausgegeben. Ist das nicht toll?