in reply to Localize lvalue subroutine.

Localize the package global first, and then call the lvalue sub:
package Foo; our $level = 1; sub level :lvalue {$Foo::level} package main; print $Foo::level; { local $Foo::level; # scalar localized... Foo->level = 2; # ...works on localized scalar print $Foo::level; } print $Foo::level; __END__ 121

I read local Foo->level = 2 as trying to localize an expression (the lvalue sub itself?), and not the package global this sub operates on.

A quick look with Scalar::Util::refaddr tells me after the local() call I am indeed dealing with the same address still.
Hmm? $Foo::level is no reference - calling Scalar::Util::refaddr on it yields undef.

--shmem

_($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                              /\_¯/(q    /
----------------------------  \__(m.====·.(_("always off the crowd"))."·
");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}

Replies are listed 'Best First'.
Re^2: Localize lvalue subroutine.
by shanna (Sexton) on Aug 06, 2007 at 14:03 UTC
    Localize the package global first, and then call the lvalue sub.

    Thanks for your time but I've confused the issue a little by using a variable accessible from the current scope. I was specifically interested in why the particular corner I've backed myself into doesn't work.
    { my $foo = 1; sub level : lvalue {$foo} } print level(); { local level() = 2; print level(); } print level(); __END__ 122

    I read local Foo->level = 2 as trying to localize an expression (the lvalue sub itself?), and not the package global this sub operates on.

    Ah that's interesting, after reading your reply I've run B::Deparse on my new example (sans our'd package variables) and the local() is removed altogether:
    { my $foo = 1; sub level : lvalue { $foo; } ; } print level(); { level() = 2; print level(); } print level();


    Hmm? $Foo::level is no reference - calling Scalar::Util::refaddr on it yields undef.


    I did \ my lvalues first :)

    My testing methods may be unorthodox but it seemed like a simple way to asses if the local() had happened like I expected and the localized Scalar::Util::refaddr \$Foo::level; now pointed at a different address.

    Presumably because perl has to create a new SV slot on the scratchpad for the inner scope the SV in question will have a different address when localized assuming everything goes well (I think I've got the lingo right?).

    Cheers,
    Shane.
      I was specifically interested in why the particular corner I've backed myself into doesn't work.
      { my $foo = 1; sub level : lvalue {$foo} } print level(); { local level() = 2; print level(); } print level(); __END__

      Because of my - it's a closure - and, as stated in perlsub

      A "local" is simply a modifier on an lvalue expression.

      No matter whether you localize the lvalue expression successfully or not, it is not the variable the lvalue sub operates on which is localized. An lvalue sub results in an lvalue upon which the operation in question is performed at subroutine return, and on the left-hand-side of the lvalue sub call you find the result of that operation. So, I guess you are effectively localizing the subroutine's return value, which isn't what you expected.

      In your code above, $foo is a lexically scoped scalar, and your subroutine is a "closure" - it closes over the scalar, which furthermore it isn't visible anywhere but in that scope, and as such can't be localized. Were you successfully operating with local upon that lexical variable, perl would have died with

      Can't localize lexical variable $foo at __FILE__ line __LINE__.

      Remember that my is a compile time directive, while local is runtime (see my/local, space/time (was: Re: The difference between my and local)).

      To localize a subroutine proper, you have to assign a coderef to its typeglob (*foo)

      { local *foo = sub : lvalue { print "wuff: $foo\n"; $foo }; }

      to make the localization effective (I guess it is optimized away otherwise, but I haven't checked that).

      Try to work out what is happening here:

      $\ = "\n"; $foo = 3; sub foo :lvalue { $foo } { local *foo = sub :lvalue { $foo *= 1.25; $foo; }; { local $foo; print '1: ',(foo() = 4); print '2: ',(foo() *= 4); foo() = 2; local *foo = sub :lvalue { local $foo = $foo * 1.25; $foo; }; print '3: ',(foo() *= 4); } local $foo = 4; print '4: ',(foo() /= 2); print '5: ',foo(); } print '6: ',foo(); __END__ 1: 4 2: 20 3: 10 4: 2.5 5: 3.125 6: 3

      All that said, an attempt to localize an lvalue sub with

      local foo() = 2;

      should result at least in a warning as

      Useless localizing of a subroutine return value

      or the like.

      --shmem

      _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                    /\_¯/(q    /
      ----------------------------  \__(m.====·.(_("always off the crowd"))."·
      ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}