Lexikalische Variable und Subroutinen
Lexikalische Variable und Subroutinen
am 20.11.2006 18:44:39 von Ferry Bolhar
Hallo,
im Code
sub a {
while (my $x = ) {
print "a: $x\n";
b();
sub b {
print "b: $x\n";
}
}
}
a();
wird die lexikalische Variable $x in der Funktion b nur das erste
mal auf denselben Wert wie in Funktion a gesetzt, danach bleibt
der alte Wert erhalten. Wenn man lange genug in der Perl Doku
sucht, findet man das auch beschrieben, bzw. gibt Perl mit -w
(use warnings) die tiefsinnige Meldung
Variable "$x" will not stay shared
aus (allerdings tut es das nur, wenn, wie im obigen Beispiel,
zwei Funktionen verschachtelt werden; mit
while (my $x = ) {
print "main: $x\n";
b();
sub b {
print "b: $x\n"; }
}
}
erlebt man denselben Effekt, bekommt aber keine Warnung).
Na schön.
Nun meine Frage: weiß jemand, _warum_ das so ist? War
das ein implementierungs-spezifisches Erfordernis? Oder
verlangen das die Regeln des statischen Scopings? Warum
wurde das so in den Interpreter einprogrammiert? Hat sich
damit schon mal jemand beschäftigt?
Danke, und schöne Grüße aus Wien,
Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: Lexikalische Variable und Subroutinen
am 20.11.2006 21:38:02 von Karlheinz Weindl
Ferry Bolhar schrieb:
> Hallo,
>
> im Code
>
> sub a {
> while (my $x = ) {
> print "a: $x\n";
> b();
> sub b {
> print "b: $x\n";
> }
> }
> }
> a();
>
> wird die lexikalische Variable $x in der Funktion b nur das erste
> mal auf denselben Wert wie in Funktion a gesetzt, danach bleibt
> der alte Wert erhalten. Wenn man lange genug in der Perl Doku
> sucht, findet man das auch beschrieben, bzw. gibt Perl mit -w
> (use warnings) die tiefsinnige Meldung
>
> Variable "$x" will not stay shared
>
> aus (allerdings tut es das nur, wenn, wie im obigen Beispiel,
> zwei Funktionen verschachtelt werden; mit
>
> while (my $x = ) {
> print "main: $x\n";
> b();
> sub b {
> print "b: $x\n"; }
> }
> }
>
> erlebt man denselben Effekt, bekommt aber keine Warnung).
> Na schön.
>
> Nun meine Frage: weiß jemand, _warum_ das so ist? War
> das ein implementierungs-spezifisches Erfordernis? Oder
> verlangen das die Regeln des statischen Scopings? Warum
> wurde das so in den Interpreter einprogrammiert? Hat sich
> damit schon mal jemand beschäftigt?
Wissen? Nein, aber laß mich mal raten!
Das ist eine "Luxus"-Warnung die davon ausgeht, dass du mit der
Variablen $x ein Closure bilden willst, das aber so nicht funktioniert.
Kh
Re: Lexikalische Variable und Subroutinen
am 20.11.2006 21:56:33 von Karlheinz Weindl
Karlheinz Weindl schrieb:
> Ferry Bolhar schrieb:
>
>
>>Hallo,
>>
>>im Code
>>
>>sub a {
>> while (my $x = ) {
>> print "a: $x\n";
>> b();
>> sub b {
>> print "b: $x\n";
>> }
>> }
>>}
>>a();
>>
>>wird die lexikalische Variable $x in der Funktion b nur das erste
>>mal auf denselben Wert wie in Funktion a gesetzt, danach bleibt
>>der alte Wert erhalten. Wenn man lange genug in der Perl Doku
>>sucht, findet man das auch beschrieben, bzw. gibt Perl mit -w
>>(use warnings) die tiefsinnige Meldung
>>
>>Variable "$x" will not stay shared
>>
>>aus (allerdings tut es das nur, wenn, wie im obigen Beispiel,
>>zwei Funktionen verschachtelt werden; mit
>>
>>while (my $x = ) {
>> print "main: $x\n";
>> b();
>> sub b {
>> print "b: $x\n"; }
>> }
>>}
>>
>>erlebt man denselben Effekt, bekommt aber keine Warnung).
>>Na schön.
>>
>>Nun meine Frage: weiß jemand, _warum_ das so ist? War
>>das ein implementierungs-spezifisches Erfordernis? Oder
>>verlangen das die Regeln des statischen Scopings? Warum
>>wurde das so in den Interpreter einprogrammiert? Hat sich
>>damit schon mal jemand beschäftigt?
>
>
> Wissen? Nein, aber laß mich mal raten!
>
> Das ist eine "Luxus"-Warnung die davon ausgeht, dass du mit der
> Variablen $x ein Closure bilden willst, das aber so nicht funktioniert.
.... aber Ernst beiseite.
Manchmal, Ferry, hilft es tatsächlich wenn man nach Fehlermeldungen sucht:
http://www.perl.com/pub/a/2002/05/07/mod_perl.html
Gruß
Kh
Karlheinz
Re: Lexikalische Variable und Subroutinen
am 21.11.2006 09:33:52 von Frank Seitz
Ferry Bolhar wrote:
> Nun meine Frage: weiß jemand, _warum_ das so ist? War
> das ein implementierungs-spezifisches Erfordernis? Oder
> verlangen das die Regeln des statischen Scopings? Warum
> wurde das so in den Interpreter einprogrammiert? Hat sich
> damit schon mal jemand beschäftigt?
Das hatte ich mich seinerzeit, als wir den Fall ausführlich
diskutiert haben, auch gefragt. Ich vermute, es hat damit
zu tun, dass es Konstrukte gibt, in denen sowas sinnvoll ist.
Die will man nicht unnötigerweise bekritteln.
Beispiel:
{
my $n = 1;
sub zaehl { $n++ }
}
Bei Schleifen-Blöcken ist es IMO allerdings nie sinnvoll,
genausowenig wie bei Subroutines. Warum das da nicht
angemeckert wird, ist mir auch nicht klar,
vielleicht lässt sich das nicht so leicht feststellen?
Grüße
Frank
--
Dipl.-Inform. Frank Seitz; http://www.fseitz.de/
Anwendungen für Ihr Internet und Intranet
Tel: 04103/180301; Fax: -02; Industriestr. 31, 22880 Wedel
Re: Lexikalische Variable und Subroutinen
am 21.11.2006 10:18:05 von Ferry Bolhar
Karlheinz Weindl:
> ... aber Ernst beiseite.
> Manchmal, Ferry, hilft es tatsächlich wenn man nach Fehlermeldungen
sucht:
>
> http://www.perl.com/pub/a/2002/05/07/mod_perl.html
Danke für den Link, der mir allerdings nicht Neues offenbart hat.
Denn manchmal, Karlheinz, geht es nicht um die Interpretation
einer Fehlermeldung, sondern darum, warum der Fehler überhaupt
auftritt bzw. ob es sich generell um einen Fehler handelt. Konkret
(aus dem obigen Link zitiert):
"When the inner power_of_2() subroutine is called for the first time, it
sees the value of the outer print_power_of_2() subroutine's $x variable. On
subsequent calls the inner subroutine's $x variable won't be updated, no
matter what new values are given to $x in the outer subroutine. There are
two copies of the $x variable, no longer a single one shared by the two
routines."
Denn die Frage, lieber Karlheinz, lautet:
Warum macht Perl das so wie in diesem Absatz beschrieben?
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: Lexikalische Variable und Subroutinen
am 21.11.2006 10:44:35 von Ingo Menger
Ferry Bolhar schrieb:
> Nun meine Frage: weiß jemand, _warum_ das so ist?
Ich denke, es ist deshalb so, weil es nicht wirklich innere benannte
Subroutinen gibt. Die Syntax täuscht das nur vor.
Wenn es sie gäbe, könnte man sie von außen nicht über ihren Namen
aufrufen, genausowenig wie man eine lokale Variable von außerhalb des
Blocks benennen kann.
Jetzt kann es folgendes überlegen: Es muß einen Unterschied geben
zwischen inneren anonymen Subroutinen und inneren benannten
Subroutinen. Die anonyme Subroutine kann ich nur verwenden, wenn ich
die äußere Subroutine aufgerufen habe, d.h. hier kann eine Closure
gebildet werden, was bedeutet: alle in der inneren anonymen Subroutine
verwendeten Lexicals bleiben einfach existent (und beim nächsten
Aufruf der äußeren Sub wird einfach eine frisches lexical-pad
benutzt). Deshalb gibt es unendlich viele mögliche Versionen der
anonymen inneren Subroutine, bei jedem Aufruf der äußeren wird eine
erzeugt.
Dies trifft für benannte Subroutinen eben nicht zu. Hier gibt es nur
eine Version und man hat sich dafür entscheiden, daß diese sozusagen
das vorweg allokierte erste lexikal Pad der äußeren benutzt und
hält, während beim zweiten Aufruf der äußeren SR wieder wie immer
ein neues Pad benutzt wird --> lexical variable does not stay shared.
Es ist völlig klar, daß das kaum anders gehen kann. Wenn ich habe:
sub outer { my $x; sub inner { $x } }
muß man entscheiden, welche der potentiell unendlich vielen Instanzen
des $x von der einen Instanz von inner benutzt werden sollen.
Dagegen bei:
my $inner =3D sub outer { my $x; sub { $x }}
ist die Sache klar: Das $x, das zur Zeit der Erzeugung der anonymen SR
exitierte, ist es.
Ich würde daher raten, innere (d.h. in einer anderen Subroutine
definierte) benannte Subroutinen überhaupt nicht zu verwenden. Man hat
Subroutinedefinition in einem Block erlaubt, um sinnvolle Konstrukte
wie
{ my $count =3D 0; sub counter { $count++; }}
zu ermöglichen, und hat in Kauf genommen, daß dieser Konstrukt nun
auch in Schleifen und anderen Subroutinen möglich ist, obwohl er dort
keinen Sinn ergibt.
Re: Lexikalische Variable und Subroutinen
am 21.11.2006 10:52:48 von Karlheinz Weindl
Ferry Bolhar schrieb:
>
> Denn die Frage, lieber Karlheinz, lautet:
>
> Warum macht Perl das so wie in diesem Absatz beschrieben?
Aah! Ich wusste nicht, dass ihr das Thema, wahrscheinlich vor kurzem
erst, schon ausführlich behandelt habt.
Du suchst also jetzt nach einer, vermutlich zwingenden Erklärung, warum
das genau so implementiert ist?
Oder warum man bei verschachtelten Subs einen freundlichen Hinweis auf
einen möglichen Fehler in seiner Programmlogik bekommt, unter anderen
Umständen aber nicht?
Zumindest die Antwort zu letzterem wirst du vermutlich nur vom Autor
selbst bekommen können.
Gruß
Karlheinz
Re: Lexikalische Variable und Subroutinen
am 21.11.2006 17:05:33 von Ferry Bolhar
Karlheinz Weindl:
> Du suchst also jetzt nach einer, vermutlich zwingenden Erklärung, warum
> das genau so implementiert ist?
Die Erklärung muss nicht "zwingend" sein. Ich wüßte nur gerne, ob hier
implementierungsspezifische Überlegungen eine Rolle gespielt haben,
oder ob es so implementiert wurde, weil ansonsten die Regeln statischen
Scopings verletzt würden.
Im letzteren Falle würde mich dann interessieren, welche Regel(n) das
wäre(n). Ich habe heute ziemlich viel über dieses Thema gegoogelt, aber
nichts gefunden, was sich konkret mit dieser Situation beschäftigt bzw.
aus dem hervorgeht, wann und unter welchen Umständen eine "Teilung"
einer lexikalischen Variable erfolgen muss.
> Oder warum man bei verschachtelten Subs einen freundlichen Hinweis auf
> einen möglichen Fehler in seiner Programmlogik bekommt, unter anderen
> Umständen aber nicht?
> Zumindest die Antwort zu letzterem wirst du vermutlich nur vom Autor
> selbst bekommen können.
Möglicherweise ein Bug - ich habe es an p5p weitergegeben. Vielleicht
ist es in der nächsten Version (5.10 - weiß jemand, wann die kommt?)
schon behoben. Der ebenfalls von mir schon früher gemeldete Fehler mit
my/our ist es jedenfalls.
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: Lexikalische Variable und Subroutinen
am 22.11.2006 10:17:11 von Ingo Menger
Ferry Bolhar schrieb:
> Möglicherweise ein Bug - ich habe es an p5p weitergegeben. Vielleicht
> ist es in der nächsten Version (5.10 - weiß jemand, wann die kommt?)
> schon behoben. Der ebenfalls von mir schon früher gemeldete Fehler mit
> my/our ist es jedenfalls.
Ferry, sag uns doch einmal, was für ein Verhalten Du erwartest: Welche
der potentiell unendlich vielen Instanzen der lokalen Variablen soll
die eine Instanz der "inneren" Subroutine denn umschließen?
Re: Lexikalische Variable und Subroutinen
am 22.11.2006 17:17:36 von Christian Winter
Karlheinz Weindl schrieb:
> Oder warum man bei verschachtelten Subs einen freundlichen Hinweis auf
> einen möglichen Fehler in seiner Programmlogik bekommt, unter anderen
> Umständen aber nicht?
> Zumindest die Antwort zu letzterem wirst du vermutlich nur vom Autor
> selbst bekommen können.
Oder aus pad.c:
/* set PAD_FAKELEX_MULTI if this lex can have multiple
* instances. For now, we just test !CvUNIQUE(cv), but
* ideally, we should detect my's declared within loops
* etc - this would allow a wider range of 'not stayed
* shared' warnings. We also treated alreadly-compiled
* lexes as not multi as viewed from evals. */
*out_flags = CvANON(cv) ?
PAD_FAKELEX_ANON :
(!CvUNIQUE(cv) && ! CvCOMPILED(cv))
? PAD_FAKELEX_MULTI : 0;
und weiter unten dann:
if (!CvCOMPILED(cv) && (*out_flags & PAD_FAKELEX_MULTI)
&& warn && ckWARN(WARN_CLOSURE)) {
newwarn = 0;
Perl_warner(aTHX_ packWARN(WARN_CLOSURE),
"Variable \"%s\" will not stay shared", name);
}
(Funktion S_pad_findlex)
Die Idee an sich ist also schon da, es hat sich nur noch niemand
gefunden, der sich die Finger daran verbrennen will.
-Christian
Re: Lexikalische Variable und Subroutinen
am 22.11.2006 18:10:33 von Karlheinz Weindl
Christian Winter schrieb:
> Oder aus pad.c:
> /* set PAD_FAKELEX_MULTI if this lex can have multiple
> * instances. For now, we just test !CvUNIQUE(cv), but
> * ideally, we should detect my's declared within loops
> * etc - this would allow a wider range of 'not stayed
> * shared' warnings. We also treated alreadly-compiled
> * lexes as not multi as viewed from evals. */
Na, iss' ja doch vom Autor ;-) oder?
Gruß
Karlheinz
Re: Lexikalische Variable und Subroutinen
am 23.11.2006 08:34:11 von Ferry Bolhar
Christian Winter:
> Oder aus pad.c:
[...]
Von welcher Perl-Version stammt das?
In "meinem" pad.c (5.8.7) kommt das nicht vor bzw. schaut die
Ausgabe der "will not stay shared" Meldung so aus:
else if (!CvUNIQUE(PL_compcv)) {
if (ckWARN(WARN_CLOSURE) && !SvFAKE(sv) && !CvUNIQUE(cv)
&& !(SvFLAGS(sv) & SVpad_OUR))
{
Perl_warner(aTHX_ packWARN(WARN_CLOSURE),
"Variable \"%s\" will not stay shared", name);
}
}
Das Problem dürfte hier das !CvUNIQUE(PL_compcv) sein.
CvUNIQUE besagt, dass der betreffende Code nur einmal
ausgeführt wird und ist u.a. bei dem CV, der den Hauptcode
repräsentiert, gesetzt. Daher ist die if-Bedingung nicht erfüllt
und die Ausgabe der Meldung unterbleibt.
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: Lexikalische Variable und Subroutinen
am 23.11.2006 22:02:29 von Christian Winter
Ferry Bolhar schrieb:
> Christian Winter:
>
>> Oder aus pad.c:
>
> [...]
>
> Von welcher Perl-Version stammt das?
Ist aus dem aktuellen Entwicklungs-Baum.
> In "meinem" pad.c (5.8.7) kommt das nicht vor bzw. schaut die
> Ausgabe der "will not stay shared" Meldung so aus:
>
> else if (!CvUNIQUE(PL_compcv)) {
> if (ckWARN(WARN_CLOSURE) && !SvFAKE(sv) && !CvUNIQUE(cv)
> && !(SvFLAGS(sv) & SVpad_OUR))
> {
> Perl_warner(aTHX_ packWARN(WARN_CLOSURE),
> "Variable \"%s\" will not stay shared", name);
> }
> }
>
> Das Problem dürfte hier das !CvUNIQUE(PL_compcv) sein.
> CvUNIQUE besagt, dass der betreffende Code nur einmal
> ausgeführt wird und ist u.a. bei dem CV, der den Hauptcode
> repräsentiert, gesetzt. Daher ist die if-Bedingung nicht erfüllt
> und die Ausgabe der Meldung unterbleibt.
IMHO ist PL_compcv der neu zu erstellende (also innere) CV. Mal
etwas im 5.8.7er Source kramen...
startcv = CvOUTSIDE(innercv);
for (cv = startcv; cv; seq = CvOUTSIDE_SEQ(cv), cv = CvOUTSIDE(cv))
Also wird beginnend beim Eltern-CV des gerade zu kompilierenden
aufwärts über den jeweiligen Parent iteriert. Die betreffende Stelle
wäre dann also !CvUNIQUE(cv).
Grunsätzlich stimmt die Schlussfolgerung aber, wie man an der
Ausgabe von folgendem Beispiel schön sieht:
use Devel::Peek;
my $z;
{
my $x = 1;
$z = sub { return $x++ }
};
Dump( $z );
Hier ist für den umgebenden lexikalischen Scope das UNIQUE Flag
wie zu erwarten gesetzt.
Viele Grüße
-Christian