Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Re: Local for lexicals (KISS)

by tye (Sage)
on Aug 10, 2009 at 20:28 UTC ( [id://787404]=note: print w/replies, xml ) Need Help??


in reply to Local for lexicals

Here is a working example that eschews all external dependencies and just "works", but requiring a less concise invocation:

#!/usr/bin/perl -w use strict; my $x = 1; my $f = sub { $x }; { my $scope= tempSet( \$x, 2 ); print $f->(), "\n"; # => 2 } print $f->(), "\n"; # => 1 sub TempSet::DESTROY { shift(@_)->() } sub tempSet { my( $sv, $new )= @_; my $prior= $$sv; my $restore= bless sub { $$sv= $prior }, 'TempSet'; $$sv= $new; return $restore; }

- tye        

Replies are listed 'Best First'.
Re^2: Local for lexicals (KISS)
by JadeNB (Chaplain) on Aug 10, 2009 at 21:02 UTC
    Unfortunately, this still (if I may use loose language) copies rather than aliasing, hence runs into trouble if $x is a tied variable (probably among other circumstances).

    Given

    sub Tie::TIESCALAR { return bless \$_[1] => $class } sub Tie::FETCH { return ${$_[0]} } sub Tie::STORE { $_[0] = "I'm not tied any more" }
    if I replace my $x = 1 by tie my $x, 'Tie', 1, then the given code blows up upon leaving the inner scope.

    UPDATE: Oops, $class should be $_[0].

      Yes, providing quite broken 'tie' implementations can make any code blow up. q-:

      Fixing your code so that it works and also demonstrates that things don't stop being tied shows that my code works fine with such things:

      #!/usr/bin/perl -w use strict; # my $x = 1; tie my $x, 'Tie', 1; my $f = sub { $x }; print $f->(), "\n"; # => 1 { my $scope= tempSet( \$x, 2 ); print $f->(), "\n"; # => 2 } print $f->(), "\n"; # => 1 sub TempSet::DESTROY { shift(@_)->() } sub tempSet { my( $sv, $new )= @_; my $prior= $$sv; my $restore= bless sub { $$sv= $prior }, 'TempSet'; $$sv= $new; return $restore; } sub Tie::TIESCALAR { return bless \$_[1] => $_[0] } sub Tie::FETCH { return "${$_[0]} is still tied at line " . (caller()) +[2] } sub Tie::STORE { ( ${$_[0]} = $_[1] ) =~ s/ is still tied at line \d+$ +// }

      which produces

      1 is still tied at line 7 2 is still tied at line 10 1 is still tied at line 12

      (Updated code to make tied-ness more apparent.)

      (Yes, in constrast, local is implemented in a way that it temporarily hides the tied nature of the localized scalar.)

      - tye        

        Fixing your code so that it works and also demonstrates that things don't stop being tied shows that my code works fine with such things …
        I agree that my code isn't a very good implementation of a tied variable, but it is what I meant (UPDATE 3: except for the silly out-of-place $class), and fixing it breaks the example. :-) (Your code doesn't quite fix it, because you try to assign to a read-only variable. Something like sub Tie::TIESCALAR { return bless \( my $o = $_[1] ) => $_[0] } would be better, I think.)

        As a less offensive example, if I replace your STORE by

        sub Tie::STORE { ${$_[0]} = $_[1] unless defined ${$_[0]} }
        then it's clear that the localisation isn't really protecting anything in the inner scope from changing:
        tie my $x, 'Tie'; my $f = sub { $x }; { my $scope = tempSet(\$x, 2); print $f->(), "\n"; # => 2 is still tied } $x = 1; print $f->(), "\n"; # => 2 is still tied
        Your comment
        Yes, in contrast, local is implemented in a way that it temporarily hides the tied nature of the localized scalar.
        hits the nail on your head—I want precisely something that has the same effect for lexicals, of setting aside their previous value, whatever that value is, and restoring it undisturbed afterwards. (In particular, $x should not be tied in the inner scope, even if it is outside.)

        UPDATE 1: Actually, testing with tie our $x, 'Tie' and an interior local $x seems to show that localisation of globals doesn't behave the way I want, either! (See Re^6: Local for lexicals (untie) for a simpler example.)
        UPDATE 2: Changed if defined test to unless defined.

Re^2: Local for lexicals (KISS)
by Roy Johnson (Monsignor) on Aug 13, 2009 at 15:25 UTC
    And here's the syntactic sugar to make the invocation concise:
    #!perl use strict; use warnings; my $x = 1; sub lambda { my $fn = pop; my @argrefs = \(@_); sub { my @scopes= map { tempSet( $argrefs[$_], $_[$_] ) } 0..$#_; &$fn; } } my $y = 'Yval'; my $closure = lambda $x, $y => sub { "$x and $y" }; print $closure->($_, rand(3)), "(X=$x, Y=$y)\n" for (qw(a bitty china +doll)); print "$x and $y\n"; # => 1 sub TempSet::DESTROY { shift(@_)->() } sub tempSet { my( $sv, $new )= @_; my $prior= $$sv; my $restore= bless sub { $$sv= $prior }, 'TempSet'; $$sv= $new; return $restore; }

    Caution: Contents may have been coded under pressure.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://787404]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others learning in the Monastery: (4)
As of 2024-03-29 00:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found