Schrift
Wiki:Tipp zum Debugging: use Data::Dumper; local $Data::Dumper::Useqq = 1; print Dumper \@var;
[thread]11322[/thread]

Gültigkeit von Variablen... oder so etwas.

Leser: 13


<< |< 1 2 3 4 >| >> 31 Einträge, 4 Seiten
theresa
 2008-02-18 13:44
#106044 #106044
User since
2007-07-17
90 Artikel
BenutzerIn
[default_avatar]
Ich füge erstmal den Kode ein, denke das lässt sich besser verstehen als eine lange Einleitung...

Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
my $zaehler = 0;
bla();

sub bla{
my $var = $zaehler++;
print "$var". "\n";
inbla();

sub inbla{
if($var<2){
bla();
}
}
}


...und der zählt $var hoch bis dass man das Programm abbricht. Was mache ich falsch? Eigentlich sollte (Absicht ist dass...) es beim 2en Durchlauf abbrechen, da $zaehler 2 wird, somit auch $var 2 wird, deswegen auch $var<2 false wird. Diese Schlussfolgerung ist falsch. Ist aber das was ich erwartet hätte...
renee
 2008-02-18 13:55
#106045 #106045
User since
2003-08-04
14371 Artikel
ModeratorIn
[Homepage] [default_avatar]
Das ist ein typischer Fall, in dem man die Sichtbarkeit (nicht Gültigkeit) der Variablen misversteht.

Eine my-Variable ist nur im aktuellen Block (die sub bla) sichtbar, local-Variablen auch in aufgerufenen Subroutinen:

perldoc perlsub
Unlike dynamic variables created by the local operator, lexical variables declared with my are totally hidden from the outside world, including any called subroutines. This is true if it's the same subroutine called from itself or elsewhere--every call gets its own copy.


Du solltest hier also local verwenden und dann funktioniert es...
OTRS-Erweiterungen (http://feature-addons.de/)
Frankfurt Perlmongers (http://frankfurt.pm/)
--

Unterlagen OTRS-Workshop 2012: http://otrs.perl-services.de/workshop.html
Perl-Entwicklung: http://perl-services.de/
pq
 2008-02-18 14:22
#106053 #106053
User since
2003-08-04
12208 Artikel
Admin1
[Homepage]
user image
ich würde hier nicht local benutzen, sondern erstmal das ganze überdenken.
zwei verschachtelte subroutinen will man in den seltensten fällen, und der code
ist für das, was er eigentlichtut, nämlich sehr wenig, wahnsinnig kompliziert und
unverständlich.
ist das so gemacht, damit der nächste maintainer den code nicht kapiert?
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live. -- Damian Conway in "Perl Best Practices"
lesen: Wiki:Wie frage ich & perlintro Wiki:brian's Leitfaden für jedes Perl-Problem
betterworld
 2008-02-18 14:30
#106058 #106058
User since
2003-08-21
2614 Artikel
ModeratorIn

user image
Ueber das Verhalten von my-Variablen in verschachtelten Subroutinen haben wir ja gerade in einem anderen Thread gesprochen. Moment, ich such mal den Link, ah da ist er ja: http://board.perl-community.de/thread/11237/

Ich wuerde Dir raten, Dich mit diesem Thema genau zu beschaeftigen, bevor Du solchen Code einsetzt.

Ach ja, und da Du die Warnung nicht erwaehnt hast, gehe ich davon aus, dass Du kein warnings einsetzt... ungut.
theresa
 2008-02-18 14:34
#106060 #106060
User since
2007-07-17
90 Artikel
BenutzerIn
[default_avatar]
pq+2008-02-18 13:22:46--
ich würde hier nicht local benutzen, sondern erstmal das ganze überdenken.
zwei verschachtelte subroutinen will man in den seltensten fällen, und der code
ist für das, was er eigentlichtut, nämlich sehr wenig, wahnsinnig kompliziert und
unverständlich.
ist das so gemacht, damit der nächste maintainer den code nicht kapiert?


Ne das ist so gemacht dafür dass es kappiert werden kann, anstatt hochzählen usw. hab ich im ursprünglichen Kode ziemlich viel drinn, was auch die "umständlichkeiten" rechtfertigt. Hab das nur soweit vereinfacht, wie es ging, dafür dass ich hier auch schnell Hilfe bekomme :)

Danke für die Hilfe renee, jetzt läuft es auch.
Warnings. Stimmt. Werde ich ab jetzt benutzen, danke für den Ratschlag.
Gast Gast
 2008-02-18 15:27
#106062 #106062
pq+2008-02-18 13:22:46--
ich würde hier nicht local benutzen, sondern erstmal das ganze überdenken.
zwei verschachtelte subroutinen will man in den seltensten fällen,


ich möchte hinzufügen: zwei verschachtelte benannte Subs will man eigentlich NIE!
Das ist ein ziemlich krankes Closure wo die Variablenbindung absolut unintuitiv wird.

Außerdem ist das innere Sub dann alles andere als local sondern im gesamten Namespace sichtbar.

grüße
KurtZ
murphy
 2008-02-18 18:07
#106071 #106071
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
Gast+2008-02-18 14:27:28--
pq+2008-02-18 13:22:46--
ich würde hier nicht local benutzen, sondern erstmal das ganze überdenken.
zwei verschachtelte subroutinen will man in den seltensten fällen,


ich möchte hinzufügen: zwei verschachtelte benannte Subs will man eigentlich NIE!
Das ist ein ziemlich krankes Closure wo die Variablenbindung absolut unintuitiv wird.
[...]


Wollen würde ich das eigentlich öfters – in jeder funktionalen Programmiersprache benutzt man verschachtelte Subroutinen alle Nase lang! In Perl würde ich es aber nicht tun weil hier meiner Meinung nach zwei fundamentale Designfehler in der Programmiersprache gemacht wurden: Zum einen sollte ein Ausbrechen nicht nur aus dem lexikalischen Namensraum sondern sogar aus dem dynamischen Namensraum, wie es bei benannten inneren Subroutinen passiert, eigentlich am besten überhaupt nicht möglich und wenn dann nicht das Standardverhalten sein. Und zum anderen fehlen die dringend nötigen Konstrukte my sub ... und local sub ... in der Sprache.

Um zum Beispiel im OP zurückzukommen, könnte man das Problem aber auch wie folgt lösen, ohne local zu bemühen:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
my $zaehler = 0;
bla();

sub bla{
    my $var = $zaehler++;

    my $inbla = sub {
        if($var<2){
            bla();
        }
    }

    print "$var". "\n";
    $inbla->();
}


Oder mit einem etwas ungewöhnlicheren Einsatz von local:
Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
my $zaehler = 0;
bla();

sub bla{
    my $var = $zaehler++;

    local *inbla = sub {
        if($var<2){
            bla();
        }
    }

    print "$var". "\n";
    inbla();
}


Edit: Oder man schreibt das ganze gleich in einer Programmiersprache die für solche Konstruktionen gedacht ist:
Code: (dl )
1
2
3
4
(let bla ((zaehler 0))
(display zaehler)
(if (< zaehler 2)
(bla (+ zaehler 1))))

;-)
When C++ is your hammer, every problem looks like your thumb.
KurtZ
 2008-02-18 18:54
#106077 #106077
User since
2007-12-13
411 Artikel
BenutzerIn
[default_avatar]
Hi Murphy

doch das geht schon in Perl lexikalisch basteln, ganz ohne local.
Die übliche Methode ist dabei anonyme Subs auf Sub_refs zu legen..

Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sub closure {
  my $abc = shift;   
  $rs_increment = sub {$abc++};    
  $rs_abc       = sub {$abc}  ;    
  print "Innen: ", &$rs_abc , "\n"; 
  ($rs_increment, $rs_abc);
}


($inc, $fetch) = closure(10);      #> Innen: 10
($inc2, $fetch2) = closure(20);  #> Innen: 20

&$inc;
&$inc;
&$inc;

print "Aussen: ",&$fetch;           #> Aussen: 13
print "Aussen: ",&$fetch2;         #> Aussen: 20


Problematisch wirds bei benannten Subs, weil sie wie du bereits sagtest
1. im aktuellen globalen Namensraum liegen.
2. was schlimmer ist, die Variablenbindung ist konfus, konkret würde statt
Code (perl): (dl )
1
2
$rs_abc= sub {}
sub abc {} 

in closure() stehen, würde immer auf die Closurevariablen des Ersten durchlaufs zugegriffen.


Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
sub closure {
  my $abc = shift;   
  $rs_increment = sub {$abc++};    
  sub abc {$abc}  ;    
  print "Innen: ", abc() , "\n"; 
  ($rs_increment, \&abc );
}


($inc, $fetch) = closure(10);                  #> Innen: 10
($inc2, $fetch2) = closure(20);              #> Innen: 10

&$inc;
&$inc;
&$inc;

print "Aussen: ",&$fetch;                      #>  Aussen: 13
print "Aussen: ",&$fetch2;                    #>  Aussen: 13


Für den OP ist das alles eh belanglos, er muss eine einfache rekursive Funktion mit Abbruchbedingung hinschreiben.


BTW: Du beherrschst die Sprache der wilden Klammerwälder und umgedrehten Notationen? ... Kannst mir mit meinem Emacs helfen? ;-)

EDIT: @Murphy: Sorry ich seh gerade die sub_ref schreibweise hast du ja auch schon beschrieben. Lesen müsste man können 8-)
( ich finde ich diese alternierenden Aufrufe von bla() und inbla() recht kryptisch - Was soll das?)
TMTOWTDYOG (there's more than one way to dig your own grave)
murphy
 2008-02-19 16:11
#106107 #106107
User since
2004-07-19
1776 Artikel
HausmeisterIn
[Homepage]
user image
KurtZ+2008-02-18 17:54:15--
[...]
BTW: Du beherrschst die Sprache der wilden Klammerwälder und umgedrehten Notationen? ... Kannst mir mit meinem Emacs helfen? ;-)


Ich kann zwar besser (CHICKEN) Scheme – bei den Sprachen aus dem Klammerwald gibt es ja unglaublich viele Dialekte – aber für die Konfigurationsdatei und einfache Macros reicht auch mein (Emacs) Lisp ;-)

Quote
EDIT: @Murphy: Sorry ich seh gerade die sub_ref schreibweise hast du ja auch schon beschrieben. Lesen müsste man können 8-)
( ich finde ich diese alternierenden Aufrufe von bla() und inbla() recht kryptisch - Was soll das?)


In dem vorliegenden Beispiel macht die innere Subroutine, die die äußere aufruft wohl nicht viel Sinn. So eine Konstruktion kann aber nützlich werden, wenn man die innere Subroutine zum Beispiel als Callback in einem Eventhandler installiert oder wenn man einen Programmteil im Continuation-passing-style schreibt.
When C++ is your hammer, every problem looks like your thumb.
KurtZ
 2008-02-19 17:45
#106114 #106114
User since
2007-12-13
411 Artikel
BenutzerIn
[default_avatar]
murphy+2008-02-19 15:11:54--
oder wenn man einen Programmteil im Continuation-passing-style schreibt.


ähm interessant... aber zwomal durchgelesen und nicht verstanden!
ein "GOTO mit Parametern" ???
TMTOWTDYOG (there's more than one way to dig your own grave)
<< |< 1 2 3 4 >| >> 31 Einträge, 4 Seiten



View all threads created 2008-02-18 13:44.