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

Hi

the primitive idea behind local is that the current value is pushed to a stack and is restored when the scope finishes.

{ push @stack,$scalar; $scalar=undef; ... some code... $scalar=shift @stack; }

But it's not that easy to simulate local for lexicals, if the var is actually tied.

Consider this example which works very well for package-vars WITHOUT interfering with tie:

package NewStdScalar; require Tie::Scalar; @ISA = qw(Tie::StdScalar); sub FETCH { return ${+shift}++ } package main; tie our $scalar, 'NewStdScalar'; $scalar=0; print $scalar; # 0 { local $scalar="---"; # --- print $scalar; } print $scalar; # 1

So is it possible to get this behavior for lexicals even if they are tied?

I'd like to implement this just with CORE-moduls, so PadWalker is not an option.

Cheers Rolf

PS: While I'm writing this I'm getting an idea how to achieve this ... but I'm open for every suggestion! :) UPDATE: Never mind, didn't work...

Replies are listed 'Best First'.
Re: localizing lexical without messing with tie ?
by ikegami (Patriarch) on Sep 08, 2010 at 02:53 UTC

    local doesn't remove the magic — the variable is still tied in the block — so

    { local $tied = 'x'; ... }
    is roughly the same as
    { my $restorer = localiser($tied, 'x'); ... }

    given a function that creates an object that restores $tied on destruction.

    use Sub::ScopeFinalizer qw( scope_finalizer ); sub localiser { my $var_ref = \$_[0]; my $saved = $$var_ref; $$var_ref = $_[1]; return scope_finalizer { $$var_ref = $saved }; }

    (Sub::ScopeFinalizer is trivial to re-implement.)

    Demonstration:

      > local doesn't remove the magic — the variable is still tied in the block

      argh you're right, I didn't test what I didn't expect... I would explicitly need to untie the localized var.

      package NewStdScalar; require Tie::Scalar; @ISA = qw(Tie::StdScalar); sub FETCH { return ${+shift}++ } package main; $\="\n"; $,="\t"; tie our $scalar, 'NewStdScalar'; sub prsc {print $scalar }; $scalar=0; prsc(); { local $scalar=42; # untie $scalar; # uncomment this to make it work prsc(); prsc(); prsc(); print $scalar; } prsc(); __DATA__ 0 42 43 44 45 1

      Sorry, ATM I'm too tired to look further into the examples you posted, later more.

      But I think I will go the simple way to exclude the use of tied variables by throwing a warning. Thx,

      Cheers Rolf

        You don't seem to know what you're looking for. At the very least, it wasn't clearly communicated. Please clarify.

        Update: Maybe it's one of these:

        Override a global package variable for a static scope:

        our $var = 'a'; { my $var = 'x'; print "$var\n"; } # x print "$var\n"; # a
        my $var = 'a'; { my $var = 'x'; print "$var\n"; } # x print "$var\n"; # a

        Override a global package variable for a dynamic scope: (Doesn't remove magic. Doesn't localise pos() except maybe on recent Perls.)

        our $var = 'a'; sub f { print "$var\n"; } { local $var = 'x'; f(); } # x print "$var\n"; # a

        Override a global package variable for a dynamic scope:

        our $var = 'a'; sub f { print "$var\n"; } { local *var; *var = 'x'; f(); } # x print "$var\n"; # a

        Override a global lexical variable for a dynamic scope:

        my $var = 'a'; sub f { print "$var\n"; } { ?????; $var = 'x'; f(); } # x print "$var\n"; # a
Re: localizing lexical without messing with tie ?
by BrowserUk (Patriarch) on Sep 08, 2010 at 03:10 UTC

    You don't need local for lexicals.

    Just shadow the name in the inner scope. So simple:

    #! perl -slw use strict; { package NewStdScalar; require Tie::Scalar; our @ISA = qw(Tie::StdScalar); sub FETCH { return ${+shift}++ } } package main; tie my $scalar, 'NewStdScalar'; $scalar=0; print $scalar; # 0 { my $scalar = "---"; # --- print $scalar; } print $scalar; # 1 __END__ C:\test>junk34 0 --- 1

    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.
      That's not equivalent since the inner variable isn't tied.

        #! perl -slw use strict; { package NewStdScalar; require Tie::Scalar; our @ISA = qw(Tie::StdScalar); sub FETCH { return ${+shift}++ } } package main; tie my $scalar, 'NewStdScalar'; $scalar=0; print $scalar; # 0 { tie my $scalar, 'NewStdScalar'; $scalar = "---"; # --- print $scalar; } print $scalar; # 1 __END__ C:\test>junk34 0 --- 1

        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.
      Trivially "shadowing" is not the point and not possible in my use case.

      I really need to localize a passed variable which is used in a passed codeblock, but your example introduces a completely new var.

      Cheers Rolf