perl 5.6: [functionname] called too early to check prototype
Calocybe
- perl
0 Jens0 Christian Kruse0 Calocybe
Hi folks!
Ich teste gerade ein kleines Programm auf verschiedenen Betriebssystemen. Dabei sind mir auch verschiedene Versionen des Perl-Interpreters untergekommen. Waehrend ich meistens eine 5.005-Version habe, laeuft auf einer Suse-Box Perl 5.6. Und so wunderte ich, als ich ploetzlich von diesem Interpreter die Warnung
main::GetFilenames() called too early to check prototype at ./xren.pl line 296vorgesetzt bekam.
Nachdem ich ein bisschen auf perldoc.com herumgesucht habe, fand ich in perldelta folgenden Text:
%s() called too early to check prototype
(W prototype) You've called a function that has a prototype before the parser saw a definition
or declaration for it, and Perl could not check that the call conforms to the prototype. You need
to either add an early prototype declaration for the subroutine in question, or move the subroutine
definition ahead of the call to get proper prototype checking. Alternatively, if you are certain that
you're calling the function correctly, you may put an ampersand before the name to avoid the
warning. See perlsub.
Mmh tja, was will er mir wohl damit sagen? Zunaechst sei gesagt, dass ich alle mein Funktionen prototype, soweit das moeglich ist, und es da auch keine Probleme gibt. Die Funktion, ueber die sich Perl beschwert, hat scheinbar nur die Besonderheit, dass sie sich selbst rekursiv aufruft. Sie sieht so aus:
sub GetFilenames($$$$;$) {
...
push(@entries, @{GetFilenames($scanpattern, 1, $basevol, $basedir, $_)}) for (@subdirs);
...
}
Offensichtlich steht die Deklaration weit VOR dem Aufruf. Damit ist doch der Prototyp bekannt, und Perl kann den Aufruf dagegen testen. Ueberhaupt frage ich mich, wie Perl wissen kann, dass eine Funktion ge-prototyped ist, wenn es noch keine Deklaration oder Definition davon gesehen hat.
Wie ich jetzt festgestellt habe, funktioniert der Check in diesem Fall tatsaechlich auch mit aelteren Versionen nicht, nur dass es dort halt keine Warnung gibt. Schade, schade. Da werde ich wohl ein & vor den Aufruf schreiben muessen, damit Perl die Warnung weglaesst. Aber eine Frage bleibt: Wer kann mir die Logik dabei erklaeren?
So long
Tach,
[Prototyp-Deklaration]
[...] See perlsub
Wer kann mir die Logik dabei erklaeren?
Wer lesen kann, ist klar im Vorteil.
perldoc perlsub.
Synopsis
Prototype declaration:
[...]
sub NAME(PROTO) BLOCK
merkst du was?
Die Lösung für dein Problem steht übrigens auch bereits in der Synopsis.
Jens
Auch Tach!
Synopsis
Prototype declaration:
[...]
sub NAME(PROTO) BLOCK
merkst du was?
Noe. Und Du?
Die Lösung für dein Problem steht übrigens auch bereits in der Synopsis.
Jetzt bin ich ja mal gespannt, ob Du das noch erklaeren kannst, oder ob Du nur wieder mal eines Deiner sinnlosen Ich-bin-Jens-und-keiner-hat-mich-lieb-Postings loswerden wolltest. Bis jetzt hast Du's zumindest noch nicht mal geschafft, richtig aus perlsub zu zitieren.
So long
Auch Tach!
Tach auch,
Synopsis
Prototype declaration:
[...]
sub NAME(PROTO) BLOCK
merkst du was?
Noe. Und Du?
schade, ich hätte mehr erwartet.
Die Prototyp-Deklaration ist erst *nach* dem Block vollzogen. Steht doch da!
Die Lösung für dein Problem steht übrigens auch bereits in der Synopsis.
Forward-Deklaration wurde ja bereits genannt. Du enttäuscht mich, wirklich.
Jens
schade, ich hätte mehr erwartet.
Die Prototyp-Deklaration ist erst *nach* dem Block vollzogen. Steht doch da!
Naja, steht in der Zeile aus Deinem Posting, aber nicht in perlsub. Dort steht:
To declare subroutines:
[...]
sub NAME BLOCK # A declaration and a definition.
sub NAME(PROTO) BLOCK # ditto, but with prototypes
Diese Zeile beschreibt also die Deklaration und Definition einer Funktion mit Prototyp. Da steht aber nicht, dass der Prototyp innerhalb des Blocks noch nicht gueltig sein darf.
Weiss nicht wo Du das her hast, was Du gepostet hast. Ist das ok fuer Dich, wenn ich mich lieber auf perlsub beziehe als auf das, was Du Dir ausgedacht hast?
Die Lösung für dein Problem steht übrigens auch bereits in der Synopsis.
Forward-Deklaration wurde ja bereits genannt. Du enttäuscht mich, wirklich.
Komisch, gerade jetzt faellt mir wieder dieser Spruch ein - wer lesen kann, ist klar im Vorteil. Wo hab ich den nur zuletzt gesehen ...? Also Du enttaeuschst mich jedenfalls nicht.
So long
Hoi Calo,
[... function called to early to check prototype ...]
Kannst du mal etwas Code posten?
Gruesse,
CK
Holla!
[... function called to early to check prototype ...]
Kannst du mal etwas Code posten?
Mmh, eigentlich dachte ich, das waere der relevante Teil gewesen. Aber gut, kann ja nebenbei gleich ein bisschen Werbung machen, hehe *g*. Also das ganze Script findet sich auf http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/xren/xren/xren.pl?rev=1.3&content-type=text/vnd.viewcvs-markup
Mmh, Slashs hinter dem Fragezeichen erlaubt? Sicherheitshalber gleich nochmal:
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/xren/xren/xren.pl?rev=1.3&content-type=text%2Fvnd.viewcvs-markup
So long
Hoi Calo,
Mmh, eigentlich dachte ich, das waere der relevante Teil gewesen.
Nee, wars nicht ;-) Der relevante Teil war im Grunde der Head.
Aber gut, kann ja nebenbei gleich ein bisschen Werbung machen, hehe
*g*.
Danke.
Mmh, Slashs hinter dem Fragezeichen erlaubt? Sicherheitshalber
gleich nochmal:
http://cvs.sourceforge.net/cgi-bin/viewcvs.cgi/xren/xren/xren.pl?rev=1.3&content-type=text%2Fvnd.viewcvs-markup
Ah, der Fehler ist klar. Auch Perl arbeitet Zeilenweise; wenn du eine
Funktion aufrufst, bei der ein Prototype-Check gemacht werden muss,
und sie wurde vorher noch nicht definiert (durch eine
Forward-Deklaration), kann der Prototyp eben nicht geprueft werden.
Das ist in C ganz aehnlich (wobei da noch viel extremer: der
Compiler geht standardmaessig davon aus, dass die Funktionsargumente
einer nicht deklarierten Funktion int-Parameter sind und dass die
Funktion int zurueck gibt). Da du die Funktion (in sich selbst)
aufrufst, bevor sie komplett analysiert wurde, wird halt dieser
Fehler erzeugt.
Die Loesung ist auch ganz einfach: oben am Script (am besten direkt
nach dem Einbinden eventueller Module) forward-Deklarationen
benutzen.
Gruesse,
CK
Hi Christian!
(Schoen, dass sich doch noch jemand mit Perlkenntnissen eingeschaltet hat. ;-))
Nee, wars nicht ;-) Der relevante Teil war im Grunde der Head.
Mmh? Den Funktionskopf mit Prototyp hatte ich doch gepostet.
Ah, der Fehler ist klar.
Find ich noch nicht. ;-)
Auch Perl arbeitet Zeilenweise; wenn du eine
Funktion aufrufst, bei der ein Prototype-Check gemacht werden muss,
und sie wurde vorher noch nicht definiert (durch eine
Forward-Deklaration), kann der Prototyp eben nicht geprueft werden.
Soweit hab ich mir das ja auch gedacht.
Da du die Funktion (in sich selbst)
aufrufst, bevor sie komplett analysiert wurde, wird halt dieser
Fehler erzeugt.
Hier bin ich nicht einverstanden. Dort wo der Aufruf steht, hat Perl den Prototyp bereits gesehen, also kann es ihn auch pruefen. Die Semantik des Prototyps aendert sich doch nicht mehr durch die Definition der Funktion. Und wenn es so waere, wie Du sagst, dann duerfte Perl ja auch nicht wissen, dass es ueberhaupt einen Prototypen gibt, gegen den es pruefen muss. Also entweder es hat ihn gesehen und weiss dass es einen gibt und kann dagegen pruefen, oder es hat ihn nicht gesehen, kann dann auch nicht pruefen, aber kann auch keine Warnung ausgeben, weil nicht bekannt ist, dass es einen Prototypen gibt.
Die Loesung ist auch ganz einfach: oben am Script (am besten direkt
nach dem Einbinden eventueller Module) forward-Deklarationen
benutzen.
Naja, Workarounds hab ich genug in der Hosentasche, daran soll's nicht scheitern. ;-) Habe mich nun doch fuer die Forwarddeklaration entschieden und direkt davor hingeschrieben, aber sinnvoll finde ich das nicht. ;-)
So long
Hoi Roland,
Nee, wars nicht ;-) Der relevante Teil war im Grunde der Head.
Mmh? Den Funktionskopf mit Prototyp hatte ich doch gepostet.
Aber nicht den Head des Scriptes.
Da du die Funktion (in sich selbst)
aufrufst, bevor sie komplett analysiert wurde, wird halt dieser
Fehler erzeugt.
Hier bin ich nicht einverstanden. Dort wo der Aufruf steht, hat
Perl den Prototyp bereits gesehen, also kann es ihn auch pruefen.
Ja, aber der Syntax-Baum fuer die Sub wurde noch nicht erstellt. Ich
denke, erst dann wird der Prototyp definiert; zumindest faende ich
das logisch: so kann erst auf syntaktische Korrektheit geprueft
werden.
Die Semantik des Prototyps aendert sich doch nicht mehr durch
die Definition der Funktion. Und wenn es so waere, wie Du sagst,
dann duerfte Perl ja auch nicht wissen, dass es ueberhaupt einen
Prototypen gibt, gegen den es pruefen muss. Also entweder es hat
ihn gesehen und weiss dass es einen gibt und kann dagegen pruefen,
oder es hat ihn nicht gesehen, kann dann auch nicht pruefen, aber
kann auch keine Warnung ausgeben, weil nicht bekannt ist, dass es
einen Prototypen gibt.
Allgemein sind eigentlich die Prototypen abgeraten (ich benutze sie
allerdings trotzdem :-), weil sie wiederum Bugs oder Gefahren mit
sich bringen. Sie scheinen nicht ganz sauber implementiert zu sein.
Naja, Workarounds hab ich genug in der Hosentasche, daran soll's
nicht scheitern. ;-)
Das ist eigentlich kein Wuergaround ;-), sondern eine ganz normale
Methode; Funktionen mit Prototypen haben im Normalfall auch
Forward-Deklarationen.
Gruesse,
CK
Re!
Mmh? Den Funktionskopf mit Prototyp hatte ich doch gepostet.
Aber nicht den Head des Scriptes.
Ach so, Du wolltest nur wissen, ob ich auch wirklich nirgendwo eine Forward declaration habe?
Hier bin ich nicht einverstanden. Dort wo der Aufruf steht, hat
Perl den Prototyp bereits gesehen, also kann es ihn auch pruefen.
Ja, aber der Syntax-Baum fuer die Sub wurde noch nicht erstellt.
Wurde er im Fall einer Forward declaration aber auch nicht.
Ich
denke, erst dann wird der Prototyp definiert; zumindest faende ich
das logisch: so kann erst auf syntaktische Korrektheit geprueft
werden.
Finde ich ueberhaupt nicht logisch. Was hat denn die syntaktische Korrektheit der Funktionsdefinition fuer eine Relevanz fuer den Prototypen?
Die Semantik des Prototyps aendert sich doch nicht mehr durch
die Definition der Funktion.
Allgemein sind eigentlich die Prototypen abgeraten (ich benutze sie
allerdings trotzdem :-), weil sie wiederum Bugs oder Gefahren mit
sich bringen.
Ich benutze sie auch schon seit Anfang an, schliesslich komme ich von C. ;-)
Aber dass davon abgeraten wird, habe ich noch nicht gehoert. Lediglich, dass man nicht wild und quer bestehende aeltere Funktionen prototypen soll, auf deren Verhalten sich jemand an anderer Stelle verlaesst (siehe dazu perlsub).
Sie scheinen nicht ganz sauber implementiert zu sein.
Das wuerde zumindest dieses seltsame Verhalten ... also nicht erklaeren, aber weniger verwunderlich machen.
Das ist eigentlich kein Wuergaround ;-),
Solange mir das Verhalten keiner zweifelsfrei logisch erklaeren kann, ist das fuer mich ein Bug. ;-)
sondern eine ganz normale
Methode; Funktionen mit Prototypen haben im Normalfall auch
Forward-Deklarationen.
Wieso das denn? Ich benutze Forwarddeklarationen praktisch nie, Prototypen dagegen soweit moeglich immer. Eigentlich braucht man sie (FwdDecl) nur, wenn zwei Funktionen sich gegenseitig aufrufen. Evtl. noch, wenn man eine Funktion verwendet, die erst zur Laufzeit nachgeladen wird und daher nicht einfach vorher mit use aus einem Modul geholt werden kann. Oder halt, wenn man diesem seltsamen Programmierstil froehnt, alle Funktionen erst nach dem Hauptprogramm zu definieren. Aber wer macht das schon ausser ein paar Unix-Hackern ... ;-)
So long
Hoi Roland,
Ach so, Du wolltest nur wissen, ob ich auch wirklich nirgendwo
eine Forward declaration habe?
Janz jenau ;-)
Wurde er im Fall einer Forward declaration aber auch nicht.
Nein, aber da wurde die Forward-Deklaration gemacht ;-)
Finde ich ueberhaupt nicht logisch. Was hat denn die syntaktische
Korrektheit der Funktionsdefinition fuer eine Relevanz fuer den
Prototypen?
Keine. Aber Perl wird in Schichten validiert, Prototypen-Fehler
muessen nicht zwingend Compile-Time-Fehler sein. Syntaktische Fehler
schon.
Ich benutze sie auch schon seit Anfang an, schliesslich komme ich
von C. ;-)
Dito.
Aber dass davon abgeraten wird, habe ich noch nicht gehoert.
Lediglich, dass man nicht wild und quer bestehende aeltere
Funktionen prototypen soll, auf deren Verhalten sich jemand an
anderer Stelle verlaesst (siehe dazu perlsub).
http://www.perl.com/pub/a/language/misc/fmproto.html
http://www.perl.com/pub/a/language/misc/bunce.html
Sie scheinen nicht ganz sauber implementiert zu sein.
Das wuerde zumindest dieses seltsame Verhalten ... also nicht
erklaeren, aber weniger verwunderlich machen.
Sie sind nachgeruestet worden, aus dem folgenden Grund:
Angenommen, man hat die Funktion sub x($). Und man ruft sie wie ein
Perl-Builtin auf:
@var = (x 1,1);
Mit einem Prototypen wird daraus
@var = (x(1),1);
Ohne wuerde daraus
@var = (x(1,1));
Das ist eigentlich kein Wuergaround ;-),
Solange mir das Verhalten keiner zweifelsfrei logisch erklaeren
kann, ist das fuer mich ein Bug. ;-)
Ich meine die Forward-Deklarationen. Sie sind kein Wuergaround. Sie
sind ein normales Sprachmittel.
sondern eine ganz normale
Methode; Funktionen mit Prototypen haben im Normalfall auch
Forward-Deklarationen.
Wieso das denn? Ich benutze Forwarddeklarationen praktisch nie,
Prototypen dagegen soweit moeglich immer.
Ich benutze Forward-Deklarationen *immer*.
Eigentlich braucht man sie (FwdDecl) nur, wenn zwei Funktionen
sich gegenseitig aufrufen. Evtl. noch, wenn man eine Funktion
verwendet, die erst zur Laufzeit nachgeladen wird und daher nicht
einfach vorher mit use aus einem Modul geholt werden kann. Oder
halt, wenn man diesem seltsamen Programmierstil froehnt, alle
Funktionen erst nach dem Hauptprogramm zu definieren. Aber wer
macht das schon ausser ein paar Unix-Hackern ... ;-)
So ziemlich viele Leute ;-)
Gruesse,
CK
Re-Hi!
Wurde er im Fall einer Forward declaration aber auch nicht.
Nein, aber da wurde die Forward-Deklaration gemacht ;-)
Ja, was willst Du mir denn jetzt sagen?
Finde ich ueberhaupt nicht logisch. Was hat denn die syntaktische
Korrektheit der Funktionsdefinition fuer eine Relevanz fuer den
Prototypen?
Keine.
Eben. Und damit gibt es keinen Grund, die "Inbetriebnahme" eines Prototyps von einem voellig peripheren Ereignis wie der Fertigstellung der Compilierung der Funktion abhaengig zu machen. In C geht's ja nu auch (weiss nich, ob der Vergleich Sinn macht).
Aber Perl wird in Schichten validiert, Prototypen-Fehler
muessen nicht zwingend Compile-Time-Fehler sein. Syntaktische Fehler
schon.
Gibt es Prototypenfehler, die zur Runtime festgestellt werden? Ich glaube eher nicht. Wie auch immer, ich verstehe nicht, was Du mir mit dem Satz sagen willst. Bin momentan aber auch ein bisschen muede.
http://www.perl.com/pub/a/language/misc/fmproto.html
http://www.perl.com/pub/a/language/misc/bunce.html
Na sieh an. Ich stimme zu, dass Prototypen in Perl in der jetzigen Form nicht gerade der grosse Wurf sind. Aber den Artikel von Tom Christiansen finde ich uebertrieben. Er scheint davon auszugehen, das Perl-Programmierer Volldeppen sind.
Sie sind nachgeruestet worden, aus dem folgenden Grund:
Bei Perl ist *alles* nachgeruestet. Dem entsprechend ist es jetzt ein ziemlicher Kraut- und Ruebenhaufen.
Ich meine die Forward-Deklarationen. Sie sind kein Wuergaround. Sie
sind ein normales Sprachmittel.
Na das ist mir klar, aber sie fuer den Fall einen ge-prototypten rekursiven Funktion anwenden zu muessen, das ist ein Workaround.
Ich benutze Forward-Deklarationen *immer*.
Wozu?
So ziemlich viele Leute ;-)
So ziemlich viele Leute ... benutzen den IE. ;-)
So long
Hi Calocybe,
Wieso das denn? Ich benutze Forwarddeklarationen praktisch nie,
Prototypen dagegen soweit moeglich immer.
Eigentlich braucht man sie (FwdDecl) nur, wenn zwei Funktionen
sich gegenseitig aufrufen.
ich komme von Pascal, nicht von C, bin aber exakt Deine Vorgehensweise gewohnt (und fände einen forward-Zwang für jede rekursive Funktion häßlich).
Und ich halte auch es für guten Stil, zuerst die aufgerufenen und danach die aufrufenden Funktionen zu deklarieren (also auf "forward" wo immer möglich zu verzichten). Ich möchte einen Quelltext gerne von vorne nach hinten lesen können, und unnötige Vorwärtsverweise erschweren das Verständnis m. E. enorm.
Viele Grüße
Michael