state in Perl 5.005?
am 20.07.2007 18:21:11 von Ferry Bolhar
Hallo,
wie hier sicher schon bekannt, wird es in Perl 5.10 einen
neuen Deklarator "state" geben, der im Prinzip dem "static" aus
C entspricht: er deklariert wie "my" eine lexikalische Variable,
die aber beim Verlassen des Scopes, in dem sie deklariert
wurde, ihren Wert behält, z.B:
sub test {
state $var;
++var;
}
print test(); # Gibt 1 aus
print test(); # Gibt 2 aus
print test(); # Gibt 3 aus
Durch einen Zufall bin ich heute daraufgekommen, wie man
auch in älteren Perl-Versionen (die im Betreff genannte ist die
Älteste, auf die ich Zugriff habe; wahrscheinlich geht's in noch
älteren Versionen genauso) das gezeigte Verhalten emulieren
kann, und zwar _ohne_ den Trick, Closures zu verwenden.
Also:
{
my $var;
sub test {
++ $var;
}
}
meine ich NICHT. Es geht auch anders, ohne Closure. Der
Trick funktioniert in 5.005, 5.6.1, 5.8.6 und 5.8.8 (andere
Versionen habe ich nicht mehr), und unter Linux, VMS, AIX
und W2000/2003.
Quasi als Revanche zu meiner vielen Fragerei lade ich euch
ein, herauszufinden, wie der Trick abläuft. Am Montag
präsentiere ich dann die Lösung. Viel Spaß beim Raten!
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: state in Perl 5.005?
am 20.07.2007 22:12:27 von Frank Seitz
Ferry Bolhar wrote:
> Quasi als Revanche zu meiner vielen Fragerei lade ich euch
> ein, herauszufinden, wie der Trick abläuft.
Ich würde es so machen:
sub test {
our $var;
++$var;
}
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: state in Perl 5.005?
am 21.07.2007 10:00:10 von Slaven Rezic
Frank Seitz writes:
> Ferry Bolhar wrote:
>
> > Quasi als Revanche zu meiner vielen Fragerei lade ich euch
> > ein, herauszufinden, wie der Trick abläuft.
>
> Ich würde es so machen:
>
> sub test {
> our $var;
> ++$var;
> }
>
"our" gibt es in perl5.005 noch nicht. Man müsste sich hier wohl mit
"use vars" begnügen.
--
Slaven Rezic - slaven rezic de
tkruler - Perl/Tk program for measuring screen distances
http://ptktools.sourceforge.net/#tkruler
Re: state in Perl 5.005?
am 23.07.2007 09:25:28 von Ferry Bolhar
Slaven Rezic:
> "our" gibt es in perl5.005 noch nicht.
So ist es, deswegen hatte ich die V5.005 extra erwähnt.
> Man müsste sich hier wohl mit "use vars" begnügen.
Nein, nein, die Variable ist schon lexikalisch. Sie wird
auch mit "my" deklariert. Aber es ist eben eine spezielle
Deklaration...
Für den Fall, dass noch jemand mitraten möchte, warte
ich mit der Auflösung noch bis morgen.
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: state in Perl 5.005?
am 23.07.2007 11:07:41 von Peter Arnhold
Ferry Bolhar schrieb:
> Slaven Rezic:
>
>> "our" gibt es in perl5.005 noch nicht.
>
> So ist es, deswegen hatte ich die V5.005 extra erwähnt.
>
>> Man müsste sich hier wohl mit "use vars" begnügen.
>
> Nein, nein, die Variable ist schon lexikalisch. Sie wird
> auch mit "my" deklariert. Aber es ist eben eine spezielle
> Deklaration...
>
> Für den Fall, dass noch jemand mitraten möchte, warte
> ich mit der Auflösung noch bis morgen.
>
> LG, Ferry
>
Getestet mit 5.005, 5.6.0 und 5.8.3 unter Win32:
#! /usr/bin/perl -w
use strict;
sub test {
!defined \&test and my $var;
++$var;
}
print test(); # 1
print test(); # 2
print test(); # 3
Gruß,
Peter
Re: state in Perl 5.005?
am 23.07.2007 21:36:20 von hjp-usenet2
On 2007-07-23 09:07, Peter Arnhold wrote:
> Getestet mit 5.005, 5.6.0 und 5.8.3 unter Win32:
>
> #! /usr/bin/perl -w
> use strict;
>
> sub test {
> !defined \&test and my $var;
> ++$var;
> }
Ja, das wird Ferry wohl gemeint haben. Die üblichere Schreibweise des
Tricks ist allerdings:
sub test {
my $var if 0;
++$var;
}
perldoc perlsyn warnt allerdings, dass das Verhalten undefiniert ist:
NOTE: The behaviour of a "my" statement modified with a statement modiâ
fier conditional or loop construct (e.g. "my $x if ...") is undefined.
The value of the "my" variable may be "undef", any previously assigned
value, or possibly anything else. Donât rely on it. Future versions
of perl might do something different from the version of perl you try
it out on. Here be dragons.
Ob die Drachen auch bei
sub test {
0 and my $var; # !defined \&test == 0
++$var;
}
hausen, kann ich der Doku nicht entnehmen, ich würde es im Zweifelsfall
aber annehmen. Beide Methoden verlassen sich darauf, dass dass die
Variable zwar angelegt, aber my() zur Laufzeit nie exekutiert wird und
tatsächlich scheint der Perl-Compiler in beiden Fällen den gleichen Code
zu generieren.
hp
--
_ | Peter J. Holzer | I know I'd be respectful of a pirate
|_|_) | Sysadmin WSR | with an emu on his shoulder.
| | | hjp@hjp.at |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"
Re: state in Perl 5.005?
am 23.07.2007 23:08:06 von Peter Arnhold
Peter J. Holzer schrieb:
> Ob die Drachen auch bei
>
> sub test {
> 0 and my $var; # !defined \&test == 0
> ++$var;
> }
>
> hausen, kann ich der Doku nicht entnehmen, ich würde es im Zweifelsfall
> aber annehmen. Beide Methoden verlassen sich darauf, dass dass die
Ja, machen sie. Wo/wann braucht man dass? Seit wann gibt es Closures? Die würde
ich klar vorziehen. Oder ging es nur um den Spaß?
Gruß,
Peter
Re: state in Perl 5.005?
am 24.07.2007 00:24:35 von hjp-usenet2
On 2007-07-23 21:08, Peter Arnhold wrote:
> Peter J. Holzer schrieb:
>> Ob die Drachen auch bei
>>
>> sub test {
>> 0 and my $var; # !defined \&test == 0
>> ++$var;
>> }
>>
>> hausen, kann ich der Doku nicht entnehmen, ich würde es im Zweifelsfall
>> aber annehmen. Beide Methoden verlassen sich darauf, dass dass die
>
> Ja, machen sie. Wo/wann braucht man dass? Seit wann gibt es Closures? Die würde
> ich klar vorziehen.
Wozu brauchst Du da Closures?
{
my $var;
sub test {
++$var;
}
}
reicht vollkommen.
> Oder ging es nur um den SpaÃ?
Muttu Ferry fragen. Quizfragen nach obskuren (Mis-)Features in
Newsgroups haben für mich jedenfalls einen gewissen SpaÃfaktor.
hp
--
_ | Peter J. Holzer | I know I'd be respectful of a pirate
|_|_) | Sysadmin WSR | with an emu on his shoulder.
| | | hjp@hjp.at |
__/ | http://www.hjp.at/ | -- Sam in "Freefall"
Re: state in Perl 5.005?
am 24.07.2007 09:49:05 von Ferry Bolhar
Peter J. Holzer:
>> sub test {
>> !defined \&test and my $var;
>> ++$var;
>> }
>
> Ja, das wird Ferry wohl gemeint haben. Die üblichere Schreibweise des
> Tricks ist allerdings:
>
> sub test {
> my $var if 0;
> ++$var;
> }
Ja, genau das habe ich gemeint.
Was hier passiert, ist, dass "my" die lexikalische Variable ganz normal
einrichtet. "my" hat jedoch auch einen Laufzeiteffekt - die Variable
bekommt zur Laufzeit eine Markierung, damit ihr Wert beim Verlassen
der Funktion verworfen und sie damit wieder auf "undef" gesetzt wird.
Und genau diese Laufzeit-Markierung wird durch das Constant Folding
wegoptimiert: der Compiler erkennt, dass die Bedingung nach "if" nie
wahr sein kann und entfernt daher die Anweisung vor dem "if" - hier
eben den Laufzeit-Teil von "my" (einen "padsv/LV_INTRO" OP).
Und somit bleibt der Wert der lexikalischen Variable auch über
Funktionsaufrufe hinweg bestehen - voilà, wir haben unser "state"
auch schon vor Perl 5.10!
Ich hab's eigentlich nur erwähnt, weil ich vor etlichen Monaten mal
mit einem Kollegen eine Diskussion hatte, der eben meinte, dass "my"
(wie auch "our", "use" und "package", um nur einige zu nennen), eine
reine Deklarationsanweisung ist, die nur von Compiler verarbeitet wird
und zur Laufzeit keine Wirkung mehr hat. Durch dieses kleine Experi-
ment, auf das ich letzte Woche zufällig beim Testen gekommen bin,
konnte ich ihm das Gegenteil beweisen.
> perldoc perlsyn warnt allerdings, dass das Verhalten undefiniert ist:
Natürlich ist das Ganze nicht dokumentiert und es ist eigentlich nur ein
Seiteneffekt, der sich einerseits aus der Art, wie "my" implementiert
ist, ergibt, und andererseits durch den Optimierungsprozess, den der
Compiler durchführt, bevor das Programm losläuft. Sollte Perl
irgendwann mal das Einrichten und Zerstören von Funktionsscopes
zur Gänze erst zur Laufzeit durchführen, wird der Trick klarerweise
nicht mehr funktionieren. Auch dann nicht, wenn es - vielleicht fürs
Debugging? - eines Tages einmal möglich sein sollte, die Optimierungs-
phase des Compilers mittels Angabe eines Switches oder eines
Pragmas zu unterdrücken oder zu beeinflussen.
Es empfiehlt sich, bei Verwendung dieses "Feature" am Beginn des
Programmes die Perl-Version abzufragen und zumindest eine
Warnungsmeldung auszugeben, wenn der Code unter ein Version
läuft, unter der das Feature noch nicht getestet wurde. Bei uns im
Haus ist das vergleichsweise einfach, da wir nur die Versionen
5.005, 5.6.1, 5.8.6 und 5.8.8 unterstützen müssen (wobei 5.8.6
und 5.8.8 im Core ziemlich ident sein dürften).
> Beide Methoden verlassen sich darauf, dass dass die
> Variable zwar angelegt, aber my() zur Laufzeit nie exekutiert wird und
> tatsächlich scheint der Perl-Compiler in beiden Fällen den gleichen Code
> zu generieren.
Ja, tut er, wie man mit B::Deparse oder B::Concise leicht überprüfen
kann. Der padsv/LV_INTRO OP wird dann einfach nicht generiert
bzw. wegoptimiert.
Rätel gelöst - Glückwunsch an die "beiden Peter": Arnold und
J. Holzer!
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: state in Perl 5.005?
am 24.07.2007 10:09:04 von Peter Arnhold
Peter J. Holzer schrieb:
> Wozu brauchst Du da Closures?
>
> {
> my $var;
>
> sub test {
> ++$var;
> }
> }
>
> reicht vollkommen.
Man liest oft von anonymen Subroutinen im Zusammenhang mit Closures. Conway
definiert o.g. Beispiel ebenfalls als Closure. Deswegen zähle ich das dazu.
Gruß,
Peter
Re: state in Perl 5.005?
am 24.07.2007 11:11:57 von Peter Arnhold
Ferry Bolhar schrieb:
> Und genau diese Laufzeit-Markierung wird durch das Constant Folding
> wegoptimiert: der Compiler erkennt, dass die Bedingung nach "if" nie
> wahr sein kann und entfernt daher die Anweisung vor dem "if" - hier
> eben den Laufzeit-Teil von "my" (einen "padsv/LV_INTRO" OP).
> Und somit bleibt der Wert der lexikalischen Variable auch über
> Funktionsaufrufe hinweg bestehen - voilà, wir haben unser "state"
> auch schon vor Perl 5.10!
Das ist ein gefährliches bugfeature. Ein "if 0" wird man kaum zufällig
schreiben, aber ich war vor Jahren Opfer meines eigenen schlechten Codes. Ich
dachte, man kann eine bedingte Initialwertzuweisung in einem Einzeiler
erledigen. Die Idee war, das $var auch bei falschem $foo angelegt wird, und
zwar mit undef. Es hat einige graue Haare gekostet, herauszufinden, warum ein
größeres Script manchmal das Falsche tat:
sub test {
my($flag) = @_;
my $var = 41 if $flag;
++$var;
}
print test(); # 1
print test(1); # 42
print test(); # 1
print test(); # 2 und nicht 1!
Es ist also nicht so, dass "der Compiler erkennt, dass die Bedingung nach "if"
*nie* wahr sein kann". Das wird erst zur Laufzeit bestimmt und immer wieder
"neu" entschieden. Leider hatte mir als Test ein einzelnes print gereicht -
alles sah gut aus :-(
Gruß,
Peter
Re: state in Perl 5.005?
am 25.07.2007 17:37:49 von Ferry Bolhar
Peter Arnhold:
> Das ist ein gefährliches bugfeature. Ein "if 0" wird man kaum zufällig
> schreiben, aber ich war vor Jahren Opfer meines eigenen schlechten Codes.
Ich
> dachte, man kann eine bedingte Initialwertzuweisung in einem Einzeiler
> erledigen. Die Idee war, das $var auch bei falschem $foo angelegt wird,
und
> zwar mit undef. Es hat einige graue Haare gekostet, herauszufinden, warum
ein
> größeres Script manchmal das Falsche tat:
>
> sub test {
> my($flag) = @_;
> my $var = 41 if $flag;
> ++$var;
> }
Ja, klar. Das ist ja das, was Peter J. Holzer gemeint und zitiert hat.
Eine solche Verwendung von "my" ist - eben wegen des versteckten
Laufzeiteffektes - gefährlich, weil niemand "my" als Befehl "Lösche
die Variable vor dem Verlassen der Funktion wieder" interpretieren
würde.
IMHO sollte der Compiler bei solchen Konstrukten einen ent-
sprechenden Hinweis ausgeben. Aber vielleicht ist das auch
zuviel verlangt, der Code des Parsers (toke.c, perly.c) ist schon
jetzt nichts für schwache Nerven!
> Es ist also nicht so, dass "der Compiler erkennt, dass die Bedingung nach
"if"
> *nie* wahr sein kann". Das wird erst zur Laufzeit bestimmt und immer
wieder
> "neu" entschieden.
Ja - für dein Beispiel. In meinem Beispiel wird der Code für den
Laufzeit-Effekt von dem "my" (der "padsv" OP) gar nicht erst
generiert, der Compiler "erkennt" das wirklich (beim "Constant
Folding", eine seiner Optimierungsphasen). Probier's aus:
$ perl -MO=Concise,-exec -e'my $x'
bzw.
$ perl -MO=Concise,-exec -e'my $x if 0'
Im zweiten Fall fehlt die Zeile
3 <0> padsv[$x:1,2] vM/LVINTRO
Dieser OP ist dafür verantwortlich, dass der entsprechende
Variablenwert beim Verlassen des Scopes gelöscht wird
(das wird durch das gesetzte LVINTRO-Flag erreicht).
Im zweiten Fall wird er gar nicht erst generiert. Bei deinem
Beispiel wird er wohl generiert, aber zur Laufzeit nicht aus-
geführt, wenn die Bedingung nicht passt.
> Leider hatte mir als Test ein einzelnes print gereicht -
> alles sah gut aus :-(
Tja, über das richtige Testen von Code sind schon ganze
Bücher (und etliche Module) geschrieben worden. Der
Abschnitt "Testing & Debugging" in PBP ist hier durchaus
empfehlenswert...
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at
Re: state in Perl 5.005?
am 25.07.2007 21:51:23 von Peter Arnhold
Ferry Bolhar schrieb:
> IMHO sollte der Compiler bei solchen Konstrukten einen ent-
> sprechenden Hinweis ausgeben. Aber vielleicht ist das auch
Schlecht wäre es nicht.
> Ja - für dein Beispiel. In meinem Beispiel wird der Code für den
> Laufzeit-Effekt von dem "my" (der "padsv" OP) gar nicht erst
> generiert, der Compiler "erkennt" das wirklich (beim "Constant
> Folding", eine seiner Optimierungsphasen). Probier's aus:
Du hast natürlich recht, was die Optimierung betrifft. Ich meinte aber was
anderes. Wenn ich dich nochmal zitieren darf:
> der Compiler erkennt, dass die Bedingung nach "if" nie
> wahr sein kann und entfernt daher die Anweisung vor dem "if" - hier
> eben den Laufzeit-Teil von "my" (einen "padsv/LV_INTRO" OP).
> Und somit bleibt der Wert der lexikalischen Variable auch über
> Funktionsaufrufe hinweg bestehen."
Die Formulierung suggeriert, das die Entfernung des Laufzeit-Teils für die
"static"-Eigenschaft verantwortlich ist. Das ist aber wirklich "nur" eine
Optimierung. Auch wenn der Laufzeit-Teil bestehen bliebe, wäre die Eigenschaft
gegeben, was mein Beispiel zeigt. "if 0" ist nur eine Teilmenge der möglichen
bedingten Deklarationen. Ein "if var/function" oder "var/function and" führt zu
keiner Optimierung und dennoch zur "static"-Eigenschaft. Entscheidend ist, dass
die Bedingung nicht wahr ist. Im Sonderfall "nie" wahr wird halt optimiert.
CMIIW.
Gruß,
Peter
Re: state in Perl 5.005?
am 26.07.2007 09:00:54 von Ferry Bolhar
Peter Arnhold:
> Die Formulierung suggeriert, das die Entfernung des Laufzeit-Teils für die
> "static"-Eigenschaft verantwortlich ist. Das ist aber wirklich "nur" eine
> Optimierung. Auch wenn der Laufzeit-Teil bestehen bliebe, wäre die
Eigenschaft
> gegeben, was mein Beispiel zeigt. "if 0" ist nur eine Teilmenge der
möglichen
> bedingten Deklarationen. Ein "if var/function" oder "var/function and"
führt zu
> keiner Optimierung und dennoch zur "static"-Eigenschaft. Entscheidend ist,
dass
> die Bedingung nicht wahr ist. Im Sonderfall "nie" wahr wird halt
optimiert.
Stimmt. Ich kam, wie gesagt, durch Zufall drauf, als ich den Runtime-Effekt
von "my", dessen Existenz von meinem Kollegen bestritten wurde, näher
zu untersuchen begann. Durch das Wegoptimieren bei "if 0" u.ä. war es
besonders leicht und anschaulich zu beweisen, dass "my" eben doch einen
Runtime-Effekt hat. Dabei habe ich möglicherweise den falschen Punkt
fokussiert, aber das hat sich ja mittlerweile geklärt.
Danke für den Hinweis!
LG, Ferry
--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol@adv.magwien.gv.at