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

I don't use local() very often -- My programming style avoids global variables when I can -- so I might not understand all the subtleties of it.

My understanding of local() is that it takes the current value of the global variable being local()ed and stores it in a hidden lexical variable, with the added semantics that the hidden lexical variable has a destrictor that restores the original value.

In otherwords:

$foo = 'foo'; sub printfoo { print $foo; } printfoo(); # prints 'foo' { local $foo = 'bar'; printfoo(); # prints 'bar' } printfoo(); # prints 'foo'
is roughly equivilant to:
$foo = 'foo'; sub printfoo { print $foo; } printfoo(); #prints 'foo' { my $hidden_foo = $foo; $foo = 'bar'; &printfoo(); #prints 'bar' $foo = $hidden_foo; } printfoo() #prints 'foo'
with the additional caveat that the $foo = $hidden_foo is always executed, regardless of how the block exits. It's effectively a destructor on $hidden_foo (which, being lexical and not being available to take references of, is destroyed when the block exits).

This masking of the original value allows you to do lots of things with $foo that you couldn't necessarily do without tromping over the original value, and messing things up for the rest of the program outside of the scope of the local().

When I posted a query like this on the perl6-language list, I got replies telling me I had missed some subtleties -- usually that the re-valuing of $foo affected dynamic sub calls within the dynamic scope of the local(). I don't think I missed that subtlety, unless there is more to it than I demonstrated above.

Am I missing anything? Are there any subtleties I don't quite get?

Replies are listed 'Best First'.
Re: YAlQ: Yet Another local() Question.
by jlistf (Monk) on Aug 03, 2000 at 18:02 UTC
    here's something you missed:
    my provides deep binding. this means that you can create closures with my. the variable will take on the value that existed when the closure was created.
    local provides shallow binding. within a closure, local will take on a value dependant on when the subroutine is called.

    sub add($); sub ladd($); my $addOne = add(1); my $laddOne = ladd(1); &$addOne(0); &$addOne(1); &$laddOne(0); &$laddOne(1); sub add($) { my $add = $_[ 0 ]; return sub { my $num = $_[ 0 ]; my $sum = $num + $add; print "$num + $add = $sum\n"; }; } sub ladd($) { local $add = $_[ 0 ]; return sub { local $num = $_[ 0 ]; local $sum = $num + $add; print "$num + $add = $sum\n"; }; }
    returns:
    0 + 1 = 1 1 + 1 = 2 0 + = 0 1 + = 1
    jeff
      Yes? How is that inconsistant with what I said? $laddOne refers to $add as a global variable. $add has no lexical definition in scope of its use in $laddOne, so it'll use the current global value.

      Granted, when the anonymous subroutine that is referenced by $laddOne was created, the global value of $add was 1, but so what? That value isn't evaluated within the -dynamic- scope of the local.

      I still don't see what I'm missing. Maybe I just came into the game late, and didn't have all the baggage associated with local() in my mind before the introduction of my(). I see local as "mask global variable" not as "create local variable". Your "counterexample" doesn't show where I'm wrong.

        i was just emphasizing the fact that my provides deep binding and local provides shallow binding. it wasn't clear (to me) from your post that you knew this.

        jeff

        Update: when you implement the transformation, the closure works again. apparently the transformation you propose doesn't actually work. or is that your point? that local provides no binding at all, but transforming it into an implementation with my does provide binding. whatever the case, local's binding is called "shallow binding" in the documentation, so thats what i'll call it here.
Re: YAlQ: Yet Another local() Question.
by mischief (Hermit) on Aug 03, 2000 at 18:44 UTC
    You might want to check out MJD's article, Coping with Scoping. -- This is not the signature you are looking for. Move along now.
      It says local() does what I think it does, it exists mainly for historical reasons, and also says "never use local(), always use my()".

      I think the last is a bit much. I find constructs like: <code> { local $\ = $RECORDSEPARATOR; $record = <INFILE>; } <code> to be quite handy, and much less unwieldy than the alternative I mentioned.

        You said:
        > I think the last is a bit much. I find constructs like: > { local $\ = $RECORDSEPARATOR; $record = ; } to be > quite handy, and much less unwieldy than the alternative > I mentioned.
        Well, yes... in which case you should check out Seven Useful Uses of local, also by mjd.
Re: YAlQ: Yet Another local() Question.
by chip (Curate) on Aug 04, 2000 at 00:15 UTC
    As far as I can tell, your writeup captures everything about local except the fact that, as an efficiency hack, Perl doesn't use assignment to implement it, but aliasing.

    In other words, local $_ is more like:

    { my $saved = \$_; my $new; *_ = \$new; # ... *_ = $saved }
    Most of the time, this has the same effect as assignment, but is faster. That's why Perl 5 uses it.

    Unfortunately, this improvement in Perl 5 actually broke some code that expected localization to be visible via all names of aliased variables (e.g. exported variables). In short, you can't usefully localize an exported variable in Perl 5. This is a Bad Thing, and I hope that Larry fixes it somehow.

    On the other hand, I hope that Larry finally fixes the name of the operator by renaming it to ``save''.

        -- Chip Salzenberg, Free-Floating Agent of Chaos

      Ah, that would also explain why there is the IMHO arbitrary restriction that you can only localize global variables, and not lexical ones. Why something like:
      { my $fh; sub init_print_log { $fh = shift;} sub print_log { print $fh scalar localtime,@_;} sub print_log_altfile { local $fh = shift; print_log(@_);} }
      is illegal, even though the -concept-, if not that particular example, is useful.

      UPDATE: Yes, save() would be a better name... better than some of the others that have been suggested. Someone also suggested renaming my() to local(). I hope that one doesn't fly.

        Actually, I have a patch that makes local() work on lexical variables. Larry didn't want to use it because he thought people would be too confused. :-(

        And I wouldn't worry about my() being renamed to local(). Larry chose the word "my" at least in part because it's short and easy to read and write.

            -- Chip Salzenberg, Free-Floating Agent of Chaos