http://www.perlmonks.org?node_id=833015

LanX has asked for the wisdom of the Perl Monks concerning the following question:

Perl still surprises me, I found this code example in B::CC

sub skip_on_odd { next NUMBER if $_[0] % 2 } NUMBER: for ($i = 0; $i < 5; $i++) { skip_on_odd($i); print $i; }
produces the output 024

I would never believe that it works because the goto and the label are in different scopes but well...

from goto I can read

... It can be used to go almost anywhere else within the dynamic scope, including out of subroutines,...

So what exactly is a "dynamic scope" here? Does it mean that the label NUMBER is kind of a localized global, which is visible in called subs?

And jumping out of the sub is guarantied to clean the call stack (such avoiding any overflows)?

So please explain why a normal call works, but not the out-commented goto call (which tries to avoid the superfluous call frame)?

sub jump { goto NESTED }; sub cont { for $i (0..3) { for $j ("a".."c") { print "$i,$j\t"; jump(); #1 #goto &jump; #2 } NESTED: } } cont();

OUTPUT1  0,a    1,a    2,a    3,a

OUTPUT2

Can't find label NESTED at /home/lanx/B/PL/PM/goto.pl line 1. 0,a

Cheers Rolf

Replies are listed 'Best First'.
Re: cross scope gotos?
by moritz (Cardinal) on Apr 06, 2010 at 11:29 UTC
    I think you are confusing two things: the normal goto, and goto &subroutine;, which are really two entirely different beasts. The latter is really tailcall. It replaces the current call frame, thus removing the current frame from the dynamic scope
    what exactly is dynamic scope?
    Dynamic scope is the current scope, plus the scope of the caller, plus the scope of the caller's caller etc.
      > It replaces the current call frame, thus removing the current frame from the dynamic scope

      which is part of the answer...

      But it's not the scoping visibility of the label variable which hinders the jump back to work like you can see in the following example:

      my $label; sub jump { goto $label ;# jump back}; sub cont { for $i (0..3) { for $j ("a".."c") { print "$i,$j\t"; $label=NESTED; #jump(); # works goto &jump; # fails } NESTED: } } cont();

      It's the point that gotos are only possible to destination within the scope of the call chain.

      BUT It may not be used to go into any construct that requires initialization, such as a subroutine or a "foreach" loop.

      Since jump() adds a new call frame, there is no more initialization of the old frame needed when jumping back, just closing the new frames.

      But with goto &jump the old call frame is replaced and all links to possible labels there!

      So jumping back would imply a re-initialization of this frame, which is not possible...

      I got it, thanks for discussing it! :)

      Cheers Rolf

        Maybe this code makes it clearer:

        sub jump { print "in\n"; goto BACK }; sub jump2 {goto &jump } sub cont { for $i (0..1) { for $j ("a".."b") { print "$i,$j\t"; jump2(); # works #goto &jump; # fails BACK: } } } cont();

        OUTPUT

        0,a in 0,b in 1,a in 1,b in
        in simple words:

        It's not only possible to jump within the same scope, but also into the scope of previous ("outer") call frames.

        (Pity I thought I found an easy pattern for continuations...)

        Cheers Rolf

Re: cross scope gotos?
by Hue-Bond (Priest) on Apr 06, 2010 at 11:28 UTC
    what exactly is dynamic scope?

    From perlsub:

    A "local" modifies its listed variables to be "local" to the enclosing + block, "eval", or "do FILE"--and to any subroutine called from within that block. A "loc +al" just gives temporary values to global (meaning package) variables. It does not cr +eate a local variable. This is known as dynamic scoping.

    I think this explains the visibility of the labels too.

    --
     David Serrano
     (Please treat my english text just like Perl code, i.e. feel free to notify me of any syntax, grammar, style and/or spelling error. Thank you!).

Re: cross scope gotos?
by BrowserUk (Patriarch) on Apr 06, 2010 at 11:53 UTC
    So what exactly is a "dynamic scope" here?

    Basically anywhere in the current program that hasn't been optimised away:

    perl -e"sub x{ goto $_[0] } bill: x( 'bill' ) " perl -e"sub x{ goto $_[0] } bill: x( 'john' ); john: goto bill;"

    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      > Basically anywhere in the current program that hasn't been optimised away:

      not that easy!

      perl -e' goto INTO; print "Start"; for $i (0..9) { INTO: print "STOP"; };' Can't "goto" into the middle of a foreach loop at -e line 4.

      You can't jump to a label out of the current or previous frames!

      see Re^3: cross scope gotos? and goto

      Cheers Rolf

        You can't jump to a label out of the current or previous frames!

        I think that's (currently) an over statement:

        perl -le"goto loop; $x=0; if( $x ){ while(1){ loop: print 'hi' } }"

        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.