Lexikalischer Scope - nächste Folge

Hallo,

folgendes Programm

use warnings;
use strict;

while (my $input = <STDIN>) {
my $sum = abs $input;
print add() . "\n";

sub add {
return $sum + $sum;
}
}

Die Funktion add() wird im lexikalischen Scope der while-Schleife
deklariert, folglich sollte immer dasselbe (lexikalische) $sum angesprochen
werden.

Man bekommt beim Kompilieren auch keinen Fehler; gibt man nach dem
ersten Prompt z.B. 33 ein, wird auch richtig 66 ausgegeben und danch wieder
gepromptet. Nur dann kann man eingeben, was man will, man bekommt
weiterhin immer nur 66 zurück! Vor und nach dem Funktionsaufruf hat $sum
aber sehr wohl den eingegebenen Wert.

Also trotz des gleichen lexikalischen Scopes nicht dieselbe Variable???

LG, Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol [at] adv.magwien.gv.at
Ferry Bolhar [ Fr, 20 Oktober 2006 18:39 ] [ ID #1508151 ]

Re: Lexikalischer Scope - nächste Folge

Ferry Bolhar schrieb:

> Hallo,
>
> folgendes Programm
>
> use warnings;
> use strict;
>
> while (my $input =3D <STDIN>) {
> my $sum =3D abs $input;
> print add() . "\n";
>
> sub add {
> return $sum + $sum;
> }
> }
>
> Die Funktion add() wird im lexikalischen Scope der while-Schleife
> deklariert, folglich sollte immer dasselbe (lexikalische) $sum angesproch=
en
> werden.

Ich wußte garnicht, daß diese Syntax geht.
Ist dann wohl ungefähr äquivalent zu

out $add;
..=2E.

$add =3D sub { $sum + $sum } unless defined $add;


man closure
Ingo Menger [ Fr, 20 Oktober 2006 19:00 ] [ ID #1508153 ]

Re: Lexikalischer Scope - nächste Folge

Ferry Bolhar wrote:

> use warnings;
> use strict;
>
> while (my $input = <STDIN>) {
> my $sum = abs $input;
> print add() . "\n";
>
> sub add {
> return $sum + $sum;
> }
> }
>
> Die Funktion add() wird im lexikalischen Scope der while-Schleife
> deklariert, folglich sollte immer dasselbe (lexikalische) $sum angesprochen
> werden.

Falsch: Die Variable $sum geht am Ende des While-Blocks aus dem Scope,
womit ihre Lebenszeit endet. Beim nächsten Durchlauf gibt es
ein neues Exemplar. add() bindet nur die erste Instanz.

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
Frank Seitz [ Fr, 20 Oktober 2006 19:34 ] [ ID #1508154 ]

Re: Lexikalischer Scope - nächsteFolge

On 2006-10-20 16:39, Ferry Bolhar <bol [at] adv.magwien.gv.at> wrote:
> Hallo,
>
> folgendes Programm
>
> use warnings;
> use strict;
>
> while (my $input = <STDIN>) {
> my $sum = abs $input;
> print add() . "\n";
>
> sub add {
> return $sum + $sum;
> }
> }
>
> Die Funktion add() wird im lexikalischen Scope der while-Schleife
> deklariert, folglich sollte immer dasselbe (lexikalische) $sum angesprochen
> werden.
>
> Man bekommt beim Kompilieren auch keinen Fehler; gibt man nach dem
> ersten Prompt z.B. 33 ein, wird auch richtig 66 ausgegeben und danch wieder
> gepromptet. Nur dann kann man eingeben, was man will, man bekommt
> weiterhin immer nur 66 zurück! Vor und nach dem Funktionsaufruf hat $sum
> aber sehr wohl den eingegebenen Wert.
>
> Also trotz des gleichen lexikalischen Scopes nicht dieselbe Variable???

So ist es. Beim ersten Schleifendurchlauf ist das von "my $sum" erzeugte
$sum und das in der sub add verwendete das gleiche. Beim zweiten
Durchlauf existiert aber noch eine Referenz auf das alte $sum (nämlich
in der sub, die ja wie alle subs global ist und nicht mit dem Verlassen
des Schleifenkörpers zerstört wird), daher erzeugt "my $sum" eine neue
Variable. $sum in der sub bezieht sich aber immer noch auf das alte
$sum. Beim dritten Durchlauf ist die im zweiten Durchlauf verwendete
unbenützt und kann recycelt werden. Das sieht man schön, wenn man sich
die Adressen ausgeben lässt:


#!/usr/bin/perl

use warnings;
use strict;

while (my $input = <STDIN>) {
my $sum = abs $input;
print "\$sum is at ", \$sum, "\n";
print add() . "\n";

sub add {
print "\$sum is at ", \$sum, "\n";
return $sum + $sum;
}
}

yoyo:~/tmp 22:14 104% ./foo
12
$sum is at SCALAR(0x8164e7c)
$sum is at SCALAR(0x8164e7c)
24
13
$sum is at SCALAR(0x814d920)
$sum is at SCALAR(0x8164e7c)
24
14
$sum is at SCALAR(0x814d920)
$sum is at SCALAR(0x8164e7c)
24
15
$sum is at SCALAR(0x814d920)
$sum is at SCALAR(0x8164e7c)
24

Das wollte ich schon im alten Thread demonstrieren, indem ich die
Änderung


#!/usr/bin/perl

use warnings;
use strict;

while (my $input = <STDIN>) {
my $sum = abs $input;
print "\$sum is at ", \$sum, "\n";

my $add = sub {
print "\$sum is at ", \$sum, "\n";
return $sum + $sum;
};

print &$add() . "\n";
}

vorschlug. Darauf ist aber IIRC keiner eingegangen.

hp

--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp [at] hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
hjp-usenet2 [ Fr, 20 Oktober 2006 22:23 ] [ ID #1508162 ]

Re: Lexikalischer Scope - nächste Folge

Peter J. Holzer wrote:
> On 2006-10-20 16:39, Ferry Bolhar <bol [at] adv.magwien.gv.at> wrote:
>>
>>Also trotz des gleichen lexikalischen Scopes nicht dieselbe Variable???
>
> So ist es. Beim ersten Schleifendurchlauf ist das von "my $sum" erzeugte
> $sum und das in der sub add verwendete das gleiche. Beim zweiten
> Durchlauf existiert aber noch eine Referenz auf das alte $sum (nämlich
> in der sub, die ja wie alle subs global ist und nicht mit dem Verlassen
> des Schleifenkörpers zerstört wird), daher erzeugt "my $sum" eine neue
> Variable. $sum in der sub bezieht sich aber immer noch auf das alte
> $sum. Beim dritten Durchlauf ist die im zweiten Durchlauf verwendete
> unbenützt und kann recycelt werden.

Für die Logik der Sache ist es unerheblich, ob Perl intern Speicher
recycled. Logisch ist es bei jedem Durchlauf eine neue Variable.
Was Du schilderst sind Implementierungsdetails, auf die die
Programmierung keinen Bezug nehmen darf.

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
Frank Seitz [ Fr, 20 Oktober 2006 23:06 ] [ ID #1508165 ]

Re: Lexikalischer Scope - nächsteFolge

On 2006-10-20 21:06, Frank Seitz <devnull4711 [at] web.de> wrote:
> Peter J. Holzer wrote:
>> On 2006-10-20 16:39, Ferry Bolhar <bol [at] adv.magwien.gv.at> wrote:
>>>
>>>Also trotz des gleichen lexikalischen Scopes nicht dieselbe Variable???
>>
>> So ist es. Beim ersten Schleifendurchlauf ist das von "my $sum" erzeugte
>> $sum und das in der sub add verwendete das gleiche. Beim zweiten
>> Durchlauf existiert aber noch eine Referenz auf das alte $sum (nämlich
>> in der sub, die ja wie alle subs global ist und nicht mit dem Verlassen
>> des Schleifenkörpers zerstört wird), daher erzeugt "my $sum" eine neue
>> Variable. $sum in der sub bezieht sich aber immer noch auf das alte
>> $sum. Beim dritten Durchlauf ist die im zweiten Durchlauf verwendete
>> unbenützt und kann recycelt werden.
>
> Für die Logik der Sache ist es unerheblich, ob Perl intern Speicher
> recycled. Logisch ist es bei jedem Durchlauf eine neue Variable.

Danke, ich wollte das eigentlich noch dazuschreiben, habe es dann aber
unterlassen.

> Was Du schilderst sind Implementierungsdetails, auf die die
> Programmierung keinen Bezug nehmen darf.

Die Programmierung nicht, aber die Erklärung - sonst wäre die nächste
Frage sicher "warum ändert sich die Adresse nach dem zweiten Durchlauf
nicht mehr?" gewesen.

hp

--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp [at] hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
hjp-usenet2 [ Sa, 21 Oktober 2006 14:52 ] [ ID #1508866 ]

Re: Lexikalischer Scope - nächste Folge

Frank Seitz:

> Falsch: Die Variable $sum geht am Ende des While-Blocks aus dem Scope,
> womit ihre Lebenszeit endet.

Ja, am _Ende_. Die Funktion add() ist aber _im_ Block
definiert und wird auch _innerhalb_ des Blocks aufgerufen.

> Beim nächsten Durchlauf gibt es
> ein neues Exemplar. add() bindet nur die erste Instanz.

Wo steht das?

LG, Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol [at] adv.magwien.gv.at
Ferry Bolhar [ Mo, 23 Oktober 2006 09:07 ] [ ID #1510760 ]

Re: Lexikalischer Scope - nächste Folge

Frank Seitz:

> Logisch ist es bei jedem Durchlauf eine neue Variable.

Nein, das ist nicht logisch, zumindest nicht, wenn man die
Definition "lexikalischer Scope" in perlsub heranzieht. Denn
dort steht sinngemäß: wird eine lexikalische Variable in
einem Schleifenkopf definiert, dann ist sie innerhalb des
gesamten Schleifenkörpers (und somit auch innerhalb
darin definierter Funktionen) sichtbar. Und für das erste
mal stimmt das ja auch. Wenn also, wie Peter schreibt,
für die Variable bei jedem Durchlauf der Schleife eine
neue Instanz angelegt wird, so wäre zu erwarten, dass das
auch für die Variable in der Funktion (die ja per Definition
_dieselbe_ lexikalische Variable ist, da sie sich im selben
Block befindet) zutrifft.

Ich dürfte da auf ein Verhalten gestoßen sein, dass in
einer ziemlichen Grauzone liegt - ich habe nirgendwo
in der Doku (auch nicht in den diversen O'Reilly Perl-
Büchern) etwas darüber gefunden, dass Variablen in
Funktionen beim ersten mal übernommen werden und
dann nicht mehr.

> Was Du schilderst sind Implementierungsdetails, auf die die
> Programmierung keinen Bezug nehmen darf.

Das ist richtig, aber es ist für das Verständnis hilfreicher.
Ich beginne jetzt zumindest mal zu verstehen, _was_
passiert, wenngleich ich immer noch nicht verstehe, _warum_
und das Verhalten für mich nicht nachvollziehbar ist.

Dennoch danke an Euch für die Antworten,

Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol [at] adv.magwien.gv.at
Ferry Bolhar [ Mo, 23 Oktober 2006 09:26 ] [ ID #1510761 ]

Re: Lexikalischer Scope - nächste Folge

Ferry Bolhar wrote:
> Frank Seitz:
>>
>>Falsch: Die Variable $sum geht am Ende des While-Blocks aus dem Scope,
>>womit ihre Lebenszeit endet.
>
> Ja, am _Ende_.

Wobei Ende hier das Ende jedes Schleifendurchlaufs meint,
nicht den Zeitpunkt des Verlassens der while-Schleife,
falls Du das annimmst.

> Die Funktion add() ist aber _im_ Block
> definiert und wird auch _innerhalb_ des Blocks aufgerufen.

Sonst würde add() die Variable nicht sehen. Ansonsten
macht die Definition einer Subroutine innerhalb eines Blocks
keinen Unterschied, die sind in Perl sowieso grundsätzlich global,
aber das ist ein anderer Punkt.

>>Beim nächsten Durchlauf gibt es
>>ein neues Exemplar. add() bindet nur die erste Instanz.
>
> Wo steht das?

In der Perl-Doku wüsste ich jetzt keine Stelle. Das ist
Informatik-Grundwissen. Stichworte: Scope und Lifetime von
Variablen.

Dass das Verhalten so abstrus erscheint, liegt nur
daran, dass Dein Code abstrus ist.

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
Frank Seitz [ Mo, 23 Oktober 2006 09:45 ] [ ID #1510763 ]

Re: Lexikalischer Scope - nächste Folge

Ferry Bolhar wrote:

> Ich dürfte da auf ein Verhalten gestoßen sein, dass in
> einer ziemlichen Grauzone liegt - ich habe nirgendwo
> in der Doku (auch nicht in den diversen O'Reilly Perl-
> Büchern) etwas darüber gefunden, dass Variablen in
> Funktionen beim ersten mal übernommen werden und
> dann nicht mehr.

Weiteres wichtiges Stichwort in dem
Zusammenhang: Closure.

Wenn Du die drei genannten Stichwörter (Scope, Liftime
und Closure) nachliest und die betreffenden Konzepte
verstanden hast, wird Dir klar, warum das alles so ist.

Perl verhält sich da, so weit ich es überblicke,
absolut korrekt und sauber.

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
Frank Seitz [ Mo, 23 Oktober 2006 10:20 ] [ ID #1510764 ]

Re: Lexikalischer Scope - nächsteFolge

On 2006-10-23 07:26, Ferry Bolhar <bol [at] adv.magwien.gv.at> wrote:
> Frank Seitz:
>> Logisch ist es bei jedem Durchlauf eine neue Variable.
>
> Nein, das ist nicht logisch, zumindest nicht, wenn man die
> Definition "lexikalischer Scope" in perlsub heranzieht.

Frank meint mit "logisch" hier "konzeptionell", nicht "intuitiv
verständlich". "Logisch", d.h., von einem abstrakten Standpunkt aus, ist
es jedesmal eine neue Variable. Der Perl-Interpreter optimiert aber die
Folge "alte Variable freigeben, neue Variable erzeugen" raus, deshalb
ist es praktisch die gleiche Variable, wenn sie freigegeben hätte
werden können (d.h., keine Referenz mehr darauf existierte).

Das ist ähnlich wie wenn Du in C ein

p = malloc(n);
free(p);
p = malloc(n);

machst. Vom Standpunkt der Sprachdefinition von C aus, bekommst Du einen
anderen Speicherbereich und auf den alten kannst Du nicht mehr
zugreifen. Je nachdem, wie free und malloc implementiert sind (und was
Du vorher gemacht hast), kann es aber durchaus sein, dass Du den
gleichen Speicherbereich wieder bekommst.

> Denn dort steht sinngemäß: wird eine lexikalische Variable in einem
> Schleifenkopf definiert, dann ist sie innerhalb des gesamten
> Schleifenkörpers (und somit auch innerhalb darin definierter
> Funktionen) sichtbar. Und für das erste mal stimmt das ja auch. Wenn
> also, wie Peter schreibt, für die Variable bei jedem Durchlauf der
> Schleife eine neue Instanz angelegt wird, so wäre zu erwarten, dass
> das auch für die Variable in der Funktion (die ja per Definition
> _dieselbe_ lexikalische Variable ist, da sie sich im selben Block
> befindet) zutrifft.

Nein, denn die Funktion wird ja nur *einmal* erzeugt, nicht bei jedem
Schleifendurchlauf neu (Wer kommt überhaupt auf die Idee, benannte
Funktionen innerhalb einer Schleife zu definieren ...). Deswegen habe
ich ja extra (schon zweimal) das Beispiel mit der anonymen sub gepostet
um zu zeigen, dass es funktioniert, weil die anonyme sub (konzeptionell,
nicht unbedingt praktisch) jedesmal eine andere ist. (Mir ist nicht
ganz klar, warum der Unterschied besteht - ich habe den Verdacht, dass
das eher eine Nebenwirkung als ein gewünschtes Verhalten ist).


> Ich dürfte da auf ein Verhalten gestoßen sein, dass in
> einer ziemlichen Grauzone liegt - ich habe nirgendwo
> in der Doku (auch nicht in den diversen O'Reilly Perl-
> Büchern) etwas darüber gefunden, dass Variablen in
> Funktionen beim ersten mal übernommen werden und
> dann nicht mehr.

perldoc perlref:

Access to lexicals that change over type--like those in the "for" loop
above--only works with closures, not general subroutines.

("over type" scheint mir ein Tippfehler zu sein, soll wohl "over time" heißen).

hp


--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp [at] hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
hjp-usenet2 [ Mo, 23 Oktober 2006 12:50 ] [ ID #1510766 ]

Re: Lexikalischer Scope - nächsteFolge

On 2006-10-23 07:45, Frank Seitz <devnull4711 [at] web.de> wrote:
> Ferry Bolhar wrote:
>> Frank Seitz:
>>>Beim nächsten Durchlauf gibt es ein neues Exemplar. add() bindet nur
>>>die erste Instanz.
>>
>> Wo steht das?
>
> In der Perl-Doku wüsste ich jetzt keine Stelle. Das ist
> Informatik-Grundwissen. Stichworte: Scope und Lifetime von
> Variablen.

Die Konzepte sind Grundwissen. Wie die jetzt in Perl genau angewandt
werden, ist aber durchaus perl-spezifisch. Das Zeug ist m.E. auch alles
irgendwo dokumentiert (zumindest habe ich noch jedes "seltsame
Verhalten" irgendwo beschrieben gefunden), wenn auch etwas verstreut.
Was aber nicht verwunderlich ist, denn "was Ferry (oder hjp) seltsam
findet" ist kein allgemein brauchbares Kapitel einer Perl-Doku. Das
Verhalten ist bei Closures beschrieben wo es inhaltlich hinpasst (wenn
ich auf finde, dass Closures nach perlsub gehören und nicht nach
perlref, aber wenigstens ist in perlsub ein Hinweis auf die richtige
Stelle).

> Dass das Verhalten so abstrus erscheint, liegt nur
> daran, dass Dein Code abstrus ist.

Da kann ich nicht widersprechen :-).

hp


--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp [at] hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
hjp-usenet2 [ Mo, 23 Oktober 2006 13:01 ] [ ID #1510768 ]

Re: Lexikalischer Scope - nächste Folge

Frank Seitz:

> Weiteres wichtiges Stichwort in dem
> Zusammenhang: Closure.

Hm, hm. Sind Closures nicht unbenannte Funktionen, die
erst zur Laufzeit erzeugt und nur über Codereferenzen
angesprochen werden? Das trifft auf meine add() Funktion
ja nicht zu.

Bei einer Closure wäre mir das Verhalten verständlicher.

> Wenn Du die drei genannten Stichwörter (Scope, Liftime
> und Closure) nachliest und die betreffenden Konzepte
> verstanden hast, wird Dir klar, warum das alles so ist.

Ich weiß nicht so recht...

> Perl verhält sich da, so weit ich es überblicke,
> absolut korrekt und sauber.

Das bezweifle ich ja nicht, ich wüßte nur gerne, _warum_
es sich so verhält. Aber wenn man von einem closure-
ähnlichem Verhalten ausgeht - der Wert einer lexikalischen
Variable wird in der Closure (= Funktion) einmal übernommen
und dann darin "eingefroren", wird es klarer.

Danke für deine Erklärung, und

LG, Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol [at] adv.magwien.gv.at
Ferry Bolhar [ Mo, 23 Oktober 2006 16:09 ] [ ID #1510772 ]

Re: Lexikalischer Scope - nächste Folge

Peter J. Holzer:

Vielen Dank für deine Erklärung!

> my $add = sub {
> print "\$sum is at ", \$sum, "\n";
> return $sum + $sum;
> };
>
> print &$add() . "\n";
> }
>
> vorschlug. Darauf ist aber IIRC keiner eingegangen.

Ich tu's jetzt: es geht auch mit

*add = sub {
..
};
print add()."\n";

dh., mit einer benannten Subroutine. Was meine Vermutung
bestätigt, dass das Besondere an einer Closure nicht deren
Anonymität ist, sondern der _Zeitpunkt_ (und damit das
lexikalische Verhalten), zu dem sie definiert wird.

sub add {$sum...}

ist eine _Deklaration_, die der _Compiler_ verarbeitet.
Es wird für $sum im Scratchpad _einmal_ ein Eintrag angelegt.
Wird - wie im Fall einer Schleife - dieser Eintrag geändert,
so muss eine Art "Clone" erfolgen - der neue Eintrag wird
für die Schleifenvariable verwendet, der alte (mit dem alten
Wert) weiterhin für die definierte Subroutine.

Ein

*add = sub{$sum...}; bzw.
$add = sub{$sum...};

ist eine _Laufzeit_anweisung. Hier werden die Werte von
außerhalb definierten lexikalischen Variablen zum Zeitpunkt
der Zuweisungsausführung übernommen. Geschieht dies
daher in einer Schleife, erfolgt die Übernahme bei jedem
Schleifendurchlauf mit den dann aktuellen Werten.

Das von dir zitierte

"Access to lexicals that change over type--like those in the "for" loop
above--only works with closures, not general subroutines."

wird damit klar, wenn man "general subroutines" mit "at compile-
time declared subroutines" bezeichnet.

Hab' ich es jetzt verstanden?

Schönen Dank für deine Geduld und Hilfe,

Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol [at] adv.magwien.gv.at
Ferry Bolhar [ Mo, 23 Oktober 2006 16:41 ] [ ID #1510773 ]

Re: Lexikalischer Scope - nächste Folge

Frank Seitz:

> Dass das Verhalten so abstrus erscheint, liegt nur
> daran, dass Dein Code abstrus ist.

Zugegeben. Aber ich finde, gerade durch solche Abstrusitäten
lernt man eine Sprache. Wenn man die einmal versteht, dann
bereitet einem "normaler" Code auch kein Kopfzerbrechen
mehr.

Und auf den bis 5.8.8 bestehenden Bug, dass ein

my $x;
our $x;

im selben Scope auch mit "use warnings" nicht reklamiert
wird, bin ich eben genau durch solchen "abstrusen" Code
gekommen.

Danke für deine Hilfe!

LG, Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol [at] adv.magwien.gv.at
Ferry Bolhar [ Mo, 23 Oktober 2006 16:46 ] [ ID #1510774 ]

Re: Lexikalischer Scope - nächsteFolge

Ferry Bolhar!

> Zugegeben. Aber ich finde, gerade durch solche Abstrusitäten
> lernt man eine Sprache. Wenn man die einmal versteht, dann
> bereitet einem "normaler" Code auch kein Kopfzerbrechen
> mehr.

Also, wenn ich ein reales Projekt bearbeite und bei einer schwer lesbaren
Codestelle denke "hey, das ist ja wie jenes abstruse Snippet von Ferry",
dann sagt das aber nichts gutes über das Projekt aus :-)


Gruß
Daniel
Daniel Fischer [ Mo, 23 Oktober 2006 16:53 ] [ ID #1510775 ]

Re: Lexikalischer Scope - nächsteFolge

On 2006-10-23 14:41, Ferry Bolhar <bol [at] adv.magwien.gv.at> wrote:
> Peter J. Holzer:
> Vielen Dank für deine Erklärung!
>
>> my $add = sub {
>> print "\$sum is at ", \$sum, "\n";
>> return $sum + $sum;
>> };
>>
>> print &$add() . "\n";
>> }
>>
>> vorschlug. Darauf ist aber IIRC keiner eingegangen.
>
> Ich tu's jetzt: es geht auch mit
>
> *add = sub {
> ..
> };
> print add()."\n";
>
> dh., mit einer benannten Subroutine.

Darüber kann man streiten. Aber Du hast den Unterschied zwischen
*add = sub {} und sub add {} im Folgenden dann eh klar gemacht.

> Was meine Vermutung bestätigt, dass das Besondere an einer Closure
> nicht deren Anonymität ist, sondern der _Zeitpunkt_ (und damit das
> lexikalische Verhalten), zu dem sie definiert wird.

Ja. Die Verwendung des Begriffs "Closure" in Perl für anonyme
Subroutinen ist ja auch nicht richtig. Im allgemeinen bezeichnet man als
Closure eine Funktion, die Zugriff auf (nicht-statische) Variablen in
einem umgebenden Scope hat. Das ist in Perl halt nur bei anonymen Subs
zuverlässig) der Fall (aus den von Dir angegeben Gründen), daher wird in
Perl "anonym" und "closure" gerne in einen Topf geworfen, obwohl das in
Wirklichkeit orthogonale Konzepte sind.

> Hab' ich es jetzt verstanden?

Ich denke schon.

hp


--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp [at] hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
hjp-usenet2 [ Mo, 23 Oktober 2006 17:33 ] [ ID #1510778 ]

Re: Lexikalischer Scope - nächste Folge

Peter J. Holzer wrote:
> On 2006-10-23 14:41, Ferry Bolhar <bol [at] adv.magwien.gv.at> wrote:
>>
>>Was meine Vermutung bestätigt, dass das Besondere an einer Closure
>>nicht deren Anonymität ist, sondern der _Zeitpunkt_ (und damit das
>>lexikalische Verhalten), zu dem sie definiert wird.
>
> Ja. Die Verwendung des Begriffs "Closure" in Perl für anonyme
> Subroutinen ist ja auch nicht richtig. Im allgemeinen bezeichnet man als
> Closure eine Funktion, die Zugriff auf (nicht-statische) Variablen in
> einem umgebenden Scope hat. Das ist in Perl halt nur bei anonymen Subs
> zuverlässig) der Fall (aus den von Dir angegeben Gründen), daher wird in
> Perl "anonym" und "closure" gerne in einen Topf geworfen, obwohl das in
> Wirklichkeit orthogonale Konzepte sind.

Ich will's mal so ausdrücken:
Kennzeichnend für eine Closure ist, dass sie ihren
Variablenkontext zum Zeitpunkt ihrer Definition einfriert
und beim Aufruf reproduziert. Ob die betreffende Funktion
benannt oder unbenannt ist oder ob ihre Definition zur
Compilezeit oder zur Laufzeit erfolgt, ist durch den
Begriff nicht festgelegt.

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
Frank Seitz [ Mo, 23 Oktober 2006 18:18 ] [ ID #1510779 ]

Re: Lexikalischer Scope - nächste Folge

Ferry Bolhar wrote:

> sub add {$sum...}
>
> ist eine _Deklaration_, die der _Compiler_ verarbeitet.
> Es wird für $sum im Scratchpad _einmal_ ein Eintrag angelegt.
> Wird - wie im Fall einer Schleife - dieser Eintrag geändert,
> so muss eine Art "Clone" erfolgen - der neue Eintrag wird
> für die Schleifenvariable verwendet, der alte (mit dem alten
> Wert) weiterhin für die definierte Subroutine.

Verstehe ich offen gestanden nicht.

> Ein
>
> *add = sub{$sum...}; bzw.
> $add = sub{$sum...};
>
> ist eine _Laufzeit_anweisung. Hier werden die Werte von
> außerhalb definierten lexikalischen Variablen zum Zeitpunkt
> der Zuweisungsausführung übernommen. Geschieht dies
> daher in einer Schleife, erfolgt die Übernahme bei jedem
> Schleifendurchlauf mit den dann aktuellen Werten.

Eine Closure bindet Variable, keine Werte.

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
Frank Seitz [ Mo, 23 Oktober 2006 18:23 ] [ ID #1510780 ]

Re: Lexikalischer Scope - nächsteFolge

On 2006-10-23 16:18, Frank Seitz <devnull4711 [at] web.de> wrote:
> Peter J. Holzer wrote:
>> On 2006-10-23 14:41, Ferry Bolhar <bol [at] adv.magwien.gv.at> wrote:
>> Ja. Die Verwendung des Begriffs "Closure" in Perl für anonyme
>> Subroutinen ist ja auch nicht richtig. Im allgemeinen bezeichnet man als
>> Closure eine Funktion, die Zugriff auf (nicht-statische) Variablen in
>> einem umgebenden Scope hat.
[...]
> Ich will's mal so ausdrücken:
> Kennzeichnend für eine Closure ist, dass sie ihren
> Variablenkontext zum Zeitpunkt ihrer Definition einfriert
> und beim Aufruf reproduziert. Ob die betreffende Funktion
> benannt oder unbenannt ist oder ob ihre Definition zur
> Compilezeit oder zur Laufzeit erfolgt, ist durch den
> Begriff nicht festgelegt.

Ja, danke. Das ist verständlicher als mein Versuch.

hp

--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp [at] hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
hjp-usenet2 [ Mo, 23 Oktober 2006 19:17 ] [ ID #1510781 ]

Re: Lexikalischer Scope - nächste Folge

Daniel Fischer:

> Also, wenn ich ein reales Projekt bearbeite und bei einer schwer lesbaren
> Codestelle denke "hey, das ist ja wie jenes abstruse Snippet von Ferry",
> dann sagt das aber nichts gutes über das Projekt aus :-)

"Schwer lesbar" bzw. "abstrus" geben IMHO subjektive
Eindrücke wieder. Was für den einen "abstrus" ist, kann für
den anderen ganz normaler Code sein. Gerade Perl mit seinen
Sigils fällt da besonders gut rein - für jemanden, der Perl nicht
kennt, wirkt eine Anweisung wie

*{$package.'::'.$name} = \&{$subname};

schnell mal abstrus. Weiß man, was dahinter steckt, sieht
das Ganze schon viel freundlicher aus.

In "realem" Code (vor allem in Code, den andere auch lesen
müssen ;-) würde ich natürlich auch versuchen, auf "Abstrusitäten"
jeder Art zu verzichten (und tue das auch). Aber zum Lernen
und Ausprobieren sind sie gerade richtig, denn wenn man erst
mal verstanden hat, was in "abstrusem" Code abläuft, dann wird
man "normalen" Code umso besser verstehen.

Und letztlich führen gerade solche "Abstrusitäten" (dh., Code,
von dem vor allem die Entwickler von Software nicht erwartet
haben, dass er je programmiert wird, der aber dennoch
funktionieren müsste) sehr oft dazu, dass Fehler im Verhalten
von Programmen entdeckt werden.

LG, Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol [at] adv.magwien.gv.at
Ferry Bolhar [ Di, 24 Oktober 2006 08:24 ] [ ID #1512155 ]

Re: Lexikalischer Scope - nächste Folge

Frank Seitz:

> Verstehe ich offen gestanden nicht.

Ich verstehe es so:

Beim ersten Aufruf wird - wie bei einer Closure - an add()
die Variable $sum weitergeben. Die Variable außerhalb und
innerhalb der Funktion enthalten denselben Wert - und auf
den wird durch Code an zwei Stellen zugegriffen, daher ist
der Referenzzähler der Variable (bzw. ihres Wertes) auf 2
gesetzt.

Beim nächsten Schleifendurchlauf soll einen neue Variable
angelegt werden. Da aber der Referenzzähler der alten
auf 2 gesetzt ist, dh., auch noch von anderem Code als von
der Schleife darauf zugegriffen wird (eben von der Funktion),
muss für die Schleife eine neue Variableninstanz (und das ab
dann bei jedem Schleifendurchlauf) erzeugt werden.

Vor bzw. beim ersten Schleifendurchlauf:

$sum RefCnt = 2 (ein $sum für Schleife und Funktion)

Ab dem zweiten Schleifendurchlauf:

$sum RefCnt = 1 ($sum für Schleife)
$sum RefCnt = 1 ($sum für Funktion)

Somit bleibt - ähnlich wie bei einer Closure - der Wert der
alten Variable "eingefroren".

>> ist eine _Laufzeit_anweisung. Hier werden die Werte von
>> außerhalb definierten lexikalischen Variablen zum Zeitpunkt
>> der Zuweisungsausführung übernommen. Geschieht dies
>> daher in einer Schleife, erfolgt die Übernahme bei jedem
>> Schleifendurchlauf mit den dann aktuellen Werten.
>
> Eine Closure bindet Variable, keine Werte.

Das habe ich auch nicht behauptet. Ich sprach von einer
_Übernahme_ der Werte von außerhalb definierten lexika-
lischen Variablen. Anders gesagt: der Vorgang des "Einfrierens"
läuft bei jedem Schleifendurchlauf mit den dann aktuellen
Variablen_Werten_ erneut ab.

LG, Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol [at] adv.magwien.gv.at
Ferry Bolhar [ Di, 24 Oktober 2006 08:40 ] [ ID #1512156 ]

Re: Lexikalischer Scope - nächste Folge

Ferry Bolhar wrote:

[Refcounts]

Die Interna habe ich mir nicht angesehen, ich
stelle mir das aber auch so vor.

> Somit bleibt - ähnlich wie bei einer Closure - der Wert der
> alten Variable "eingefroren".

Wieso "ähnlich wie bei einer Closure"?
Das ist eine Closure.

>>Eine Closure bindet Variable, keine Werte.
>
> Das habe ich auch nicht behauptet. Ich sprach von einer
> _Übernahme_ der Werte von außerhalb definierten lexika-
> lischen Variablen. Anders gesagt: der Vorgang des "Einfrierens"
> läuft bei jedem Schleifendurchlauf mit den dann aktuellen
> Variablen_Werten_ erneut ab.

Es werden keine Werte übernommen, sondern die jeweilige
Variable wird - wie oben - an die generierte Funktion
(Closure) gebunden. Nur eben zur Laufzeit.

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
Frank Seitz [ Di, 24 Oktober 2006 12:16 ] [ ID #1512157 ]

Re: Lexikalischer Scope - nächste Folge

Ferry Bolhar wrote:

[Refcounts]

Die Interna habe ich mir nicht angesehen, ich
stelle mir das aber auch so vor.

> Somit bleibt - ähnlich wie bei einer Closure - der Wert der
> alten Variable "eingefroren".

Wieso "ähnlich wie bei einer Closure"?
Das ist eine Closure.

>>Eine Closure bindet Variable, keine Werte.
>
> Das habe ich auch nicht behauptet. Ich sprach von einer
> _Übernahme_ der Werte von außerhalb definierten lexika-
> lischen Variablen. Anders gesagt: der Vorgang des "Einfrierens"
> läuft bei jedem Schleifendurchlauf mit den dann aktuellen
> Variablen_Werten_ erneut ab.

Es werden keine Werte übernommen, sondern die jeweilige
Variable wird - wie oben - an die generierte Funktion
(Closure) gebunden. Nur eben zur Laufzeit.
Beachte: Bei jedem Schleifendurchlauf wird eine
neue Funktion generiert.

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
Frank Seitz [ Di, 24 Oktober 2006 12:23 ] [ ID #1512158 ]

Re: Lexikalischer Scope - nächsteFolge

On 2006-10-24 06:24, Ferry Bolhar <bol [at] adv.magwien.gv.at> wrote:
> Daniel Fischer:
>> Also, wenn ich ein reales Projekt bearbeite und bei einer schwer
>> lesbaren Codestelle denke "hey, das ist ja wie jenes abstruse Snippet
>> von Ferry", dann sagt das aber nichts gutes über das Projekt aus :-)
>
> "Schwer lesbar" bzw. "abstrus" geben IMHO subjektive
> Eindrücke wieder. Was für den einen "abstrus" ist, kann für
> den anderen ganz normaler Code sein. Gerade Perl mit seinen
> Sigils fällt da besonders gut rein - für jemanden, der Perl nicht
> kennt, wirkt eine Anweisung wie
>
> *{$package.'::'.$name} = \&{$subname};
>
> schnell mal abstrus.

Das ist allerdings (meiner Meinung nach) nicht wegen der Sigils
"abstrus", sondern wegen der Manipulation der Symboltabelle zur
Laufzeit. Das ist manchmal durchaus sinnvoll, aber ein recht deftiger
Eingriff in das Laufzeitverhalten, das nicht irgendwo in der Mitte von
"harmlosem" Code versteckt werden sollte.

hp (der kein besonderer Freund von Sigils ist)


--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp [at] hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
hjp-usenet2 [ Di, 24 Oktober 2006 17:21 ] [ ID #1512160 ]

Re: Lexikalischer Scope - nächste Folge

Ferry Bolhar wrote:

> Gerade Perl mit seinen
> Sigils fällt da besonders gut rein - für jemanden, der Perl nicht
> kennt, wirkt eine Anweisung wie
>
> *{$package.'::'.$name} =3D \&{$subname};
>
> schnell mal abstrus.

Auch für jemanden, der Perl kennt.

> Weiß man, was dahinter steckt, sieht
> das Ganze schon viel freundlicher aus.

Ich möchte lieber gar nicht daran denken, was dahinter stecken könnte
..=2E.


> In "realem" Code (vor allem in Code, den andere auch lesen
> müssen ;-) würde ich natürlich auch versuchen, auf "Abstrusitäten"
> jeder Art zu verzichten (und tue das auch). Aber zum Lernen
> und Ausprobieren sind sie gerade richtig, denn wenn man erst
> mal verstanden hat, was in "abstrusem" Code abläuft, dann wird
> man "normalen" Code umso besser verstehen.

Naja, jedem Tierchen sein Pläsierchen, sag ich mal.
Ich persönlich habe, als ich zu der Stelle der perldoc kam, wo das
*-Zeug erklärt wird, beschlossen, daß ich so was nie brauchen werde
und deshalb nicht wissen muß.
Ingo Menger [ Di, 24 Oktober 2006 17:38 ] [ ID #1512161 ]

Re: Lexikalischer Scope - nächsteFolge

Ferry Bolhar!

> *{$package.'::'.$name} = \&{$subname};
>
> schnell mal abstrus. Weiß man, was dahinter steckt, sieht
> das Ganze schon viel freundlicher aus.

Code, der mit use strict nicht erlaubt ist, ist per definitionem abstrus.


Gruß
Daniel
Daniel Fischer [ Di, 24 Oktober 2006 18:18 ] [ ID #1512162 ]

Re: Lexikalischer Scope - nächste Folge

Daniel Fischer wrote:
> Ferry Bolhar!
>>
>>*{$package.'::'.$name} = \&{$subname};
>>
>>schnell mal abstrus. Weiß man, was dahinter steckt, sieht
>>das Ganze schon viel freundlicher aus.
>
> Code, der mit use strict nicht erlaubt ist, ist per definitionem abstrus.

Dann wäre Perls Importmechanismus abstrus und beinah sämtlicher
Code der auf Symboltabellen operiert. Ich finde es nicht
gut, dass use strict diesen Fall anmeckert und frage mich jedes
einzige Mal, was man sich dabei gedacht hat. Eine andere Form,
einen Zugriff auf einen Typeglob mit variablen Anteilen
(oben $package und $name) auszudrücken, wüsste ich nicht.

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
Frank Seitz [ Di, 24 Oktober 2006 20:03 ] [ ID #1512163 ]

Re: Lexikalischer Scope - nächste Folge

Daniel Fischer <spam [at] erinye.com> writes:

> Ferry Bolhar!
>
> > *{$package.'::'.$name} = \&{$subname};
> >
> > schnell mal abstrus. Weiß man, was dahinter steckt, sieht
> > das Ganze schon viel freundlicher aus.
>
> Code, der mit use strict nicht erlaubt ist, ist per definitionem abstrus.
>

Wie generiert ihr denn ansonsten Getter/Setter?

Gruß,
Slaven

--
Slaven Rezic - slaven <at> rezic <dot> de

Visualize Makefiles with GraphViz:
http://user.cs.tu-berlin.de/~eserte/src/perl/GraphViz-Makefi le/
Slaven Rezic [ Di, 24 Oktober 2006 19:56 ] [ ID #1512164 ]

Re: Lexikalischer Scope - nächste Folge

Frank Seitz:

>> Somit bleibt - ähnlich wie bei einer Closure - der Wert der
>> alten Variable "eingefroren".
>
> Wieso "ähnlich wie bei einer Closure"?
> Das ist eine Closure.

Nein. Eine Closure wird erst zur Laufzeit, wenn sie
zugewiesen wird, compiliert. In einem Konstrukt wie

while (my $input = <STDIN>) {
my $sum = abs $input;
print add();
sub add {
$sum + $sum;
}
}

wird add() mit dem anderen Code gemeinsam kompiliert.
Daher war das Verhalten des "Einfrierens" der beim ersten
mal übergebenen Werte für mich ja auch nicht sofort nach-
vollziehbar. Peter hat das anhand der Referenzcounter
der Variablen erst (für mich :-) verständlich gemacht.

> Es werden keine Werte übernommen, sondern die jeweilige
> Variable wird - wie oben - an die generierte Funktion
> (Closure) gebunden. Nur eben zur Laufzeit.

Eben. Und in meinem (obigen) Code ist das nicht der Fall.

> Beachte: Bei jedem Schleifendurchlauf wird eine
> neue Funktion generiert.

Wobei ich annehmen würde, das Perl den kompilierten Code
cacht und beim "Neu generieren" nur die aktullen Werte der
lexikalischen Variable einsetzt (aus Effizienzgründen). Aber das
ist ein implementierungs-spezifisches Detail.

LG, Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol [at] adv.magwien.gv.at
Ferry Bolhar [ Mi, 25 Oktober 2006 13:00 ] [ ID #1513580 ]

Re: Lexikalischer Scope - nächste Folge

Ferry Bolhar schrieb:
> Frank Seitz:
>
>>> Somit bleibt - ähnlich wie bei einer Closure - der Wert der
>>> alten Variable "eingefroren".
>> Wieso "ähnlich wie bei einer Closure"?
>> Das ist eine Closure.
>
> Nein. Eine Closure wird erst zur Laufzeit, wenn sie
> zugewiesen wird, compiliert.

Wo steht das?

-Christian
Christian Winter [ Mi, 25 Oktober 2006 14:05 ] [ ID #1513581 ]

Re: Lexikalischer Scope - nächste Folge

Ich schrieb:

> folgendes Programm

[...]

Ein letzter Hinweis noch dazu:

wenn man den Code selbst ebenfalls als "sub" deklariert
und dann aufgerufen hätte, also

sub mainsub {
> while (my $input = <STDIN>) {
> my $sum = abs $input;
> print add() . "\n";
>
> sub add {
> return $sum + $sum;
> }
> }
}
mainsub();

hätte Perl passenderweise die Meldung

Variable "$sum" will not stay shared...

ausgegeben, die das Verhalten um einiges klarer macht.
Eigenartigerweise tut es das nur, wenn der Code, der
die Unterfunktion (hier: add()) aufruft, selbst innerhalb
einer Funktion läuft. Bug oder Feature?

LG, Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol [at] adv.magwien.gv.at
Ferry Bolhar [ Mi, 25 Oktober 2006 15:16 ] [ ID #1513583 ]

Re: Lexikalischer Scope - nächste Folge

Ferry Bolhar wrote:

> Ein letzter Hinweis noch dazu:
>
> wenn man den Code selbst ebenfalls als "sub" deklariert
> und dann aufgerufen hätte, also
>
> sub mainsub {
> > while (my $input = <STDIN>) {
> > my $sum = abs $input;
> > print add() . "\n";
> >
> > sub add {
> > return $sum + $sum;
> > }
> > }
> }
> mainsub();
>
> hätte Perl passenderweise die Meldung
>
> Variable "$sum" will not stay shared...
>
> ausgegeben, die das Verhalten um einiges klarer macht.
> Eigenartigerweise tut es das nur, wenn der Code, der
> die Unterfunktion (hier: add()) aufruft, selbst innerhalb
> einer Funktion läuft. Bug oder Feature?

Ich finde, es ist ein Feature, dass Perl das Problem (Stichwort:
abstruse Programmierung) zumindest innerhalb eines
Subroutine-Scope erkennt. Warum Perl es im Scope eines
while-Blocks nicht erkennt (oder nicht als Problem bewertet),
weiß ich nicht. Für mich ist es auf den ersten Blick dasselbe.

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
Frank Seitz [ Mi, 25 Oktober 2006 15:48 ] [ ID #1513584 ]

Re: Lexikalischer Scope - nächste Folge

Ferry Bolhar wrote:
> Frank Seitz:
>>
>>Wieso "ähnlich wie bei einer Closure"?
>>Das ist eine Closure.
>
> Nein. Eine Closure wird erst zur Laufzeit, wenn sie
> zugewiesen wird, compiliert.

Mir stellt sich dieselbe Frage wie Christian Winter.

> while (my $input = <STDIN>) {
> my $sum = abs $input;
> print add();
> sub add {
> $sum + $sum;
> }
> }
[...]
>>Es werden keine Werte übernommen, sondern die jeweilige
>>Variable wird an die generierte Funktion
>>(Closure) gebunden. Nur eben zur Laufzeit.
>
> Eben. Und in meinem (obigen) Code ist das nicht der Fall.

Doch. Der Mechanismus ist in beiden Fällen der gleiche.

>>Beachte: Bei jedem Schleifendurchlauf wird eine
>>neue Funktion generiert.
>
> Wobei ich annehmen würde, das Perl den kompilierten Code
> cacht und beim "Neu generieren" nur die aktullen Werte der
> lexikalischen Variable einsetzt (aus Effizienzgründen). Aber das
> ist ein implementierungs-spezifisches Detail.

Nein, das macht Perl mit Sicherheit nicht, denn dann
wäre es keine Closure.

Zum dritten Mal: Eine Closure bindet Variable, keine Werte.
Folgender Code macht es vielleicht klarer:

#!/usr/local/bin/perl -w

use strict;

my ($f,$ref);
{
my $n = 7;
$ref = \$n;
$f = sub { print "$n\n"};
$f->();
}
$$ref = 8;
$f->();
__END__
7
8

Dasselbe Spiel kannst Du auch mit Deinem ursprünglichen
add() machen.

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
Frank Seitz [ Mi, 25 Oktober 2006 16:03 ] [ ID #1513585 ]

Re: Lexikalischer Scope - nächste Folge

Christian Winter:

>> Nein. Eine Closure wird erst zur Laufzeit, wenn sie
>> zugewiesen wird, compiliert.
>
> Wo steht das?

Na, wenn ich Frank richtig verstanden habe, in seinem
Posting:

> Beachte: Bei jedem Schleifendurchlauf wird eine
> neue Funktion generiert

Das kann ja wohl nur zur Laufzeit sein, oder?

LG, Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol [at] adv.magwien.gv.at
Ferry Bolhar [ Mi, 25 Oktober 2006 18:18 ] [ ID #1513587 ]

Re: Lexikalischer Scope - nächste Folge

Frank Seitz:

>> Nein. Eine Closure wird erst zur Laufzeit, wenn sie
>> zugewiesen wird, compiliert.
>
> Mir stellt sich dieselbe Frage wie Christian Winter.

Wie du selbst geschrieben hast:

>>>Beachte: Bei jedem Schleifendurchlauf wird eine
>>>neue Funktion generiert.

Da eine Schleife erst zur Laufzeit durchlaufen wird, wird
auch die entsprechende Funktion (Closure) erst dann
generiert, oder nicht?

> Doch. Der Mechanismus ist in beiden Fällen der gleiche.

Nicht ganz. Bei Closures wird eine lexikalische Variable
zur Laufzeit, wenn die Closure erzeugt und die Referenz
darauf an einen Skalar oder Typeglob zugewiesen wird,
mit dem dann gerade befindlichen Wert übernommen. Dass
man den, wie du weiter unten gezeigt hast, über eine Referenz
von "außen" ändern kann, ändert ja am Prinzip selber nichts.
OK, ich habe begriffen, was du zeigen wolltest, dass tat-
sächlich Variable, die man nachträglich über Referenzen
ändern kann, übernommen werden, und keine nicht ver-
ändernbaren Werte.

Eine benannte Funktion wird kompiliert, wenn das übrige
Programm kompiliert wird. Zu diesem Zeitpunkt haben
allfällige Variable ($sum in meinem Beispiel) ja noch keinen
Wert. Es wird also, um bei deiner Diktion zu bleiben, eine
"leere" Variable übernommen. Zur Laufzeit wird diese Variable
mit einem Wert versehen, der auch innerhalb der Funktion existiert.
Wird der lexikalischen Variable dann ein anderer Wert zugewiesen,
erfolgt praktisch ein "Splitting" - aus einer Variable sind plötzlich
zwei geworden, und Perl weist darauf ja auch mit seiner "will not
stay shared" Meldung (von der ich jetzt erst eigentlich richtig
begreife, was sie aussagt und unter welchen Umständen sie ausge-
geben wird) darauf hin. Und dieses "Splitting" gibt es bei Closures,
die erst zur Laufzeit kompiliert werden, nicht. _Das_ ist der
Unterschied.

Unklar ist mir noch - jetzt geht's wieder um Implementierungs-
fragen - woher Perl weiß, wann es dieses Splitting machen muss.
Möglicherweise hat es etwas mit dem auch bei Typeglobs ver-
wendeten FAKE-Mechanismus zu tun - wird ein Typeglob einem
Skalar zugewiesen

$x = *y;

so enthält der Skalar zunächst tatsächlich den Typeglob, der
Wert ist aber als FAKE gekennzeichnet. Wird später der
Typeglob im Skalar modifiziert, zB.

*{$x}{CODE} = sub {...};

so wird er vom ursprünglichen Typeglob abgespalten und es
entsteht ein neuer, veränderter Typeglob. FAKE ist hier also
etwas ähnliches wie ein Copy-On-Reference-Mechanismus
im Memory-Management - mehrere Komponenten greifen
auf ein- und denselben Speicher lesend zu; sobald eine
Komponente den Speicher modifiert, erhält sie vorher eine
private Kopie und kann auf den ursprünglichen, gemeinsamen
Speicher nicht mehr zugreifen.

Ich könnte mir denken, dass der Compiler beim Zugriff auf eine
lexikalische Variable, die in einem anderen (äußeren) Scope
deklariert wurde, diese ebenfalls als "FAKE" markiert.
Änderungen an einer Variable führen dann zu einem Splitting.

LG, Ferry

--
Ing Ferry Bolhar
Magistrat der Stadt Wien - MA 14
A-1010 Wien
E-Mail: bol [at] adv.magwien.gv.at
Ferry Bolhar [ Mi, 25 Oktober 2006 18:43 ] [ ID #1513588 ]

Re: Lexikalischer Scope - nächsteFolge

On 2006-10-25 16:18, Ferry Bolhar <bol [at] adv.magwien.gv.at> wrote:
> Christian Winter:
>>> Nein. Eine Closure wird erst zur Laufzeit, wenn sie
>>> zugewiesen wird, compiliert.
>>
>> Wo steht das?
>
> Na, wenn ich Frank richtig verstanden habe, in seinem
> Posting:
>
>> Beachte: Bei jedem Schleifendurchlauf wird eine
>> neue Funktion generiert
>
> Das kann ja wohl nur zur Laufzeit sein, oder?

Ja, aber mit "generiert" meinte Frank vermutlich nicht "compiliert". Es
würde mich wundern, wenn die Funktion tatsächlich jedesmal neu
compiliert wird. Es wird wohl nur ein neuer Kontext für den bereits
compilierten Code erzeugt.

hp


--
_ | Peter J. Holzer | > Wieso sollte man etwas erfinden was nicht
|_|_) | Sysadmin WSR | > ist?
| | | hjp [at] hjp.at | Was sonst wäre der Sinn des Erfindens?
__/ | http://www.hjp.at/ | -- P. Einstein u. V. Gringmuth in desd
hjp-usenet2 [ Mi, 25 Oktober 2006 19:15 ] [ ID #1513589 ]

Re: Lexikalischer Scope - nächste Folge

Ferry Bolhar schrieb:
> Christian Winter:
>
>>> Nein. Eine Closure wird erst zur Laufzeit, wenn sie
>>> zugewiesen wird, compiliert.
>> Wo steht das?
>
> Na, wenn ich Frank richtig verstanden habe, in seinem
> Posting:
>
>> Beachte: Bei jedem Schleifendurchlauf wird eine
>> neue Funktion generiert
>
> Das kann ja wohl nur zur Laufzeit sein, oder?

Nope, das kann auch durch Kopieren erfolgen.

Viele Grüße
-Christian
Christian Winter [ Do, 26 Oktober 2006 07:38 ] [ ID #1514976 ]

Re: Lexikalischer Scope - nächste Folge

Ferry Bolhar wrote:

>>>Nein. Eine Closure wird erst zur Laufzeit, wenn sie
>>>zugewiesen wird, compiliert.
>
> Wie du selbst geschrieben hast:
>
>>>>Beachte: Bei jedem Schleifendurchlauf wird eine
>>>>neue Funktion generiert.

Generieren heißt nicht unbedingt kompilieren.
Und Closures entstehen nicht notwendig zur Laufzeit.
Denn es geht auch anders:

my $ref;
{
my $n = 7;
$ref = \$n;
sub f { print "$n\n"}
f;
}
$$ref = 8;
f;
__END__
7
8

f() ist hier eine Closure, die nicht zur Laufzeit,
sondern zur Compilezeit entsteht. Der Code
verhält sich exakt genauso wie dieser:

my ($f,$ref);
{
my $n = 7;
$ref = \$n;
$f = sub { print "$n\n"};
$f->();
}
$$ref = 8;
$f->();
__END__
7
8

> Wird der lexikalischen Variable dann ein anderer Wert zugewiesen,
> erfolgt praktisch ein "Splitting" - aus einer Variable sind plötzlich
> zwei geworden,

Wie kommst Du darauf? Bei der Zuweisung passiert garnichts.
Neue Variable entstehen, wenn ein Block betreten wird, und dieser
lokale Variable definiert. Dieselben Variablen werden
vernichtet, wenn der Block verlassen wird. Es sei denn, sie
werden anderweitig referenziert, z.B. durch eine Closure.

> und Perl weist darauf ja auch mit seiner "will not
> stay shared" Meldung (von der ich jetzt erst eigentlich richtig
> begreife, was sie aussagt und unter welchen Umständen sie ausge-
> geben wird) darauf hin.

Ich sehe das so: Perl weist mit der Meldung darauf hin,
dass wenn die äußere Variable erstmalig aus dem Scope gegangen ist,
die innere Subroutine nur noch mit dieser - für die Außenwelt
verstorbenen - Variable weiterarbeitet, also als Closure fungiert.
Das ist ziemlich sicher nicht das, was intendiert ist,
also gibt es die Meldung.

> Und dieses "Splitting" gibt es bei Closures,
> die erst zur Laufzeit kompiliert werden, nicht. _Das_ ist der
> Unterschied.

Bei einer dynamisch erzeugten Closure gibt es obigen Effekt
nicht, da die Funktionen ja immer passend zu den äußeren
Variableninstanzen erzeugt werden. Da geschieht also ziemlich sicher
das, was intendiert ist, also gibt es keine Meldung.

> Unklar ist mir noch - jetzt geht's wieder um Implementierungs-
> fragen - woher Perl weiß, wann es dieses Splitting machen muss.

[Perl-Interna]

Es ist sicherlich schwer, abstrakte Konzepte aus den
Perl-Interna herzuleiten, das kann leicht in die Irre führen.
Ich mache das deshalb garnicht. Teilweise denken und
argumentieren wir wohl auf unterschiedlichen Ebenen.

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
Frank Seitz [ Do, 26 Oktober 2006 09:52 ] [ ID #1514977 ]

Re: Lexikalischer Scope - nächste Folge

Frank Seitz wrote:
> Ferry Bolhar wrote:
> > ausgegeben, die das Verhalten um einiges klarer macht.
> > Eigenartigerweise tut es das nur, wenn der Code, der
> > die Unterfunktion (hier: add()) aufruft, selbst innerhalb
> > einer Funktion läuft. Bug oder Feature?
>
> Ich finde, es ist ein Feature, dass Perl das Problem (Stichwort:
> abstruse Programmierung) zumindest innerhalb eines
> Subroutine-Scope erkennt. Warum Perl es im Scope eines
> while-Blocks nicht erkennt (oder nicht als Problem bewertet),
> weiß ich nicht. Für mich ist es auf den ersten Blick dasselbe.

Ack. Allerdings könnte man perl vorwerfen, daß er die Definition
einer benannten sub unterhalb der obersten Ebene warnungslos erlaubt
und somit Bolhar'sche Mißverständnisse geradezu provoziert. Ich kann
mir denken, daß das deshalb klaglos geht, weil ja auch eval "sub foo
{=2E...}" gehen muß wenn es irgendwo in den Tiefen aufgerufen wird.
Ingo Menger [ Do, 26 Oktober 2006 11:44 ] [ ID #1514978 ]
Perl » de.comp.lang.perl.misc » Lexikalischer Scope - nächste Folge

Vorheriges Thema: PHP?
Nächstes Thema: [Windows] mehrere Dateien an "perl -pi.bak -e"übergeben