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

Suppose I tie() a variable. Is it possible from the FETCH handler to get my hands on the tied variable (!not the object implementing it, the actual variable!), untie it and store the result there?

This would be really handy in the Data::Lazy module. Currently when you FETCH the value of the scalar variable the first time it computes the value, stores it in the object, returns it and then it behaves exactly as an ordinary variable. Except that it's still tied and therefore much slower :-(

Thanks, Jenda
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
   -- Rick Osborne

Replies are listed 'Best First'.
Re: How to untie oneself?
by tilly (Archbishop) on Jul 10, 2003 at 21:16 UTC
    Unless you want to mess around with the internals, I don't see how this is possible.

    However it is possible to achieve the same effect by having your tie method accept an optional reference which will have the value stored, and then export utility methods that use it. So you might wind up with something like this interface:

    promise(\ my $result_of_long_compute, sub { # Long computation here });
    and then you implement this along the following lines:
    sub promise { my ($to_tie, $implement, $opts); if (UNIVERSAL::isa($to_tie, 'SCALAR')) { tie $$to_tie, Data::Lazy, $implement, $opts; } elsif (UNIVERSAL::isa($to_tie, 'HASH')) { ... }
    And then document that using the promise() utility function is faster than using the tie interface.

      Hmmm ... strange. That doesn't seem to work. I tried the additional parameter, I even tried to add a ref to the tied variable to the object later and it did not work. The variable appeared not to be tied within FETCH and stayed tied outside:

      ---------testUntie.pl--------- #!perl use Data::Lazy; print "ref=" . \$x . "\n"; tie $x, 'Data::Lazy', sub {sleep 1; 2}; tied($x)->{'var'} = \$x; print "Tied: " . tied($x) . "\n"; print "\$x=$x\n"; print "Tied: " . tied($x) . "\n"; print "\$x=$x\n"; ---------Data/Lazy.pm--------- package Data::Lazy; #... sub TIESCALAR { my $pack = shift; my $self = {}; $self->{code} = shift; $self->{'store'} = $_[0] if $_[0]; $self->{'type'} = 0; # $self->{'var'} = $_[1] if $_[1]; bless $self => $pack; # That's it? Yup! } #... sub FETCH { my $self = shift; if ($self->{'type'} == 0) { # scalar return $self->{value} if exists $self->{value}; if (ref $self->{code} eq 'CODE') { $self->{value} = &{$self->{code}}; } else { $self->{value} = eval $self->{code}; } if ($self->{'store'} == LAZY_STOREVALUE and exists $self->{'var'}) +{ my $var = $self->{'var'}; print "Try to untie $var tied to " . tied($$var) . "\n"; untie($$var); $$var = $self->{value}; undef $self; return $$var; } else { $self->{value}; } } # ... elsif array and hash } #... 1;
      and it prints
      ref=SCALAR(0x1a4587c) Tied: Data::Lazy=HASH(0x15d55d0) Try to untie SCALAR(0x1a4587c) tied to $x=2 Tied: Data::Lazy=HASH(0x15d55d0) $x=2
      That is I do have a reference to the right scalar, yet it's not tied ?!?

      I use Perl 5.8 (ActivePerl build 805) under Win2000serverSP4.

      I also tried the same code using Perl 5.6.1 (ActivePerl build 631, same OS) and there it also did not report the reference to be tied, but did succeed to untie it:

      ref=SCALAR(0x1ab2cc0) Tied: Data::Lazy=HASH(0x1abf078) Try to untie SCALAR(0x1ab2cc0) tied to $x=2 Tied: $x=2
      Strange.

      Jenda
      Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
         -- Rick Osborne

      Edit by castaway: Closed small tag in signature

        Bizarre.

        I guess that this is tied to the internal implementation of tie. Which I have long thought of as a leaking bandage over a self-inflicted wound.

        I guess the moral is that you shouldn't push tie very far because it isn't very robust. :-(

Re: How to untie oneself?
by BrowserUk (Patriarch) on Jul 10, 2003 at 22:15 UTC

    You don't mention what kind of variable you are tying, though you do mention scalar later in your post, so this extract from the Perl 5.8 delta pod may or may not be relavent.

    Self-tying Problems

    Self-tying of arrays and hashes is broken in rather deep and hard-to-fix ways. As a stop-gap measure to avoid people from getting frustrated at the mysterious results (core dumps, most often), it is forbidden for now (you will get a fatal error even from an attempt).

    A change to self-tying of globs has caused them to be recursively referenced (see: Two-Phased Garbage Collection in the perlobj manpage). You will now need an explicit untie to destroy a self-tied glob. This behaviour may be fixed at a later date.

    Self-tying of scalars and IO thingies works.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller


      I don't think I know what do they mean by self-tying. In either case the only type for which the untieing I want would make sense are scalars (ok maybe FILEHANDLEs as well, but Data::Lazy doesn't support that just now, and I don't think it ever will). Anyway thanks for warning me :-)

      Jenda
      Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
         -- Rick Osborne

      Edit by castaway: Closed small tag in signature

Re: How to untie oneself?
by Juerd (Abbot) on Jul 10, 2003 at 21:16 UTC

    The only way I know of is using symbolic references. Perl crashes if you pass tie a reference to the variable that you are tieing.

    See PLP::Tie::Delay.

    Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

      Can you offer a snippet demonstrating this crash?

      If this is true, then the approach that I offered above can still be made to work - just have promise() take the return of tying the variable and then stuff the ref to the original into that.

        Strange. I thought I replied yesterday.

        I thought perl -e'sub TIESCALAR { } tie $foo, main, \$foo' would crash, but it doesn't with both 5.6.1 and 5.8.0. I'm sure it (or something similar) did crash in earlier versions, because I recall having discussed it on Magnet #perl, where several wizards said is was a known problem.

        Or I had a very bad nightmare. If that is the case, I wonder how PLP::Tie::Delay escaped dreamworld :)

        Juerd # { site => 'juerd.nl', plp_site => 'plp.juerd.nl', do_not_use => 'spamtrap' }

Re: How to untie oneself?
by runrig (Abbot) on Jul 11, 2003 at 17:35 UTC
    Here is what I tried. I think its similar to what you've tried above. Its odd but convienient that after untie'ing you are left with a variable that has the same value as was last returned from FETCH. (At least on my perl v5.6.1). So you don't need to pass a reference to the variable in order to set it after the untie (here it is accessed through a closure).
    use strict; use warnings; package MyTied; sub TIESCALAR { my ($class,$code) = @_; bless $code, $class; } sub FETCH { my $self = shift; print "Untie\n"; $self->(); } package main; my $var; tie $var, 'MyTied', sub { untie $var; 4 }; print "One\n"; print "$var\n"; print "Two\n"; print "$var\n"; print "Three\n"; print "$var\n"; OUTPUT: One Untie 4 Two 4 Three 4
    Updated. several times.

      Thanks. This works fine using Perl 5.6.1, but doesn't work under Perl 5.8. Under Perl 5.8 it prints:

      One Untie 4 Two Untie 4 Three Untie 4
      :-(((

      I tried to untie a different variable within the sub{} and that works, but untieing the variable whose FETCH handler is being processed simply doesn't work :-(

      Jenda
      Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
         -- Rick Osborne

      Edit by castaway: Closed small tag in signature

Re: How to untie oneself?
by DrHyde (Prior) on Jul 11, 2003 at 08:36 UTC
    I'm really not 100% clear on what it is that you want to do. However, perhaps the tied function might be useful? It gives you a reference to the underlying object.

      No. I need to go the other way around. From the object to the tied variable :-)

      Jenda
      Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
         -- Rick Osborne

      Edit by castaway: Closed small tag in signature