Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

untie() and tied() and UNTIE dont work right inside FETCH with tied scalar

by patcat88 (Deacon)
on Feb 16, 2011 at 13:24 UTC ( #888501=perlquestion: print w/ replies, xml ) Need Help??
patcat88 has asked for the wisdom of the Perl Monks concerning the following question:

I am trying to make a tied scalar, that on its first FETCH, will turn itself back into a normal untied scalar and then set itself to the result of a sub in its parent object where the tied/untied scalar lives as a hash slice. The point is, the value has to be generated just once, only the first time. No point in keeping it tied for the rest of the life of myObj object. Its an attempt at efficiency. The weaken is to prevent a memleak/circular reference. mytie class MUST obtain the permanent value of the tied scalar from myObj/its parent.

The reason I am using a tied scalar verse a GetValue() method on myObj is, myObj is a large complicated object with inheritance and everything. Its less bug inducing to make $self->{'tiedScalar'} a tied scalar for a short while, than change hundreds of places where $self->{'tiedScalar'} is accessed among multiple modules.

The problem is, that tied() doesn't work inside the FETCH method. untie() does work, but it never calls UNTIE method.
#!/usr/bin/perl -w package mytie; use Scalar::Util qw( weaken ); sub TIESCALAR { print "TIESCALAR\n"; my $class = shift; my $self = {'myiobj' => shift}; weaken($self->{'myiobj'}); return bless($self, $class); } sub FETCH { print "FETCH\n"; my $obj = $_[0]->{'myiobj'}; print "going to untie\n"; print "tied() is ".tied($obj->{'tiedScalar'})."\n"; untie($obj->{'tiedScalar'}); print "tied() is ".tied($obj->{'tiedScalar'})."\n"; print "untied\n"; $obj->{'tiedScalar'} = $obj->GetFinalValue(); } sub STORE { print "STORE\n"; } sub DESTROY { print "DESTROY\n"; } sub UNTIE { print "UNTIE\n"; } package myObj; sub new { bless({'tiedScalar'=> undef, 'finalValScalar' => "final value\n"} +); } sub tiescalar { my $self = shift; tie($self->{'tiedScalar'}, 'mytie', $self); } sub untiescalar { my $self = shift; untie($self->{'tiedScalar'}); } sub GetFinalValue { my $self = shift; return $self->{'finalValScalar'}; } sub DESTROY { print "myObj destroyed\n"; } package main; { my $o = myObj::new(); $o->tiescalar(); #comment one and uncomment the other below print '$o->{\'tiedScalar\'} is '.$o->{'tiedScalar'}; #$o->untiescalar(); print tied($o->{'tiedScalar'})?"tiedScalar is still tied\n":"tied +Scalar is now untied\n"; } 0;
with "print '$o->{\'tiedScalar\'} is '.$o->{'tiedScalar'};" I get
C:\Documents and Settings\Owner\Desktop>perl n8.pl TIESCALAR FETCH going to untie Use of uninitialized value in concatenation (.) or string at n8.pl lin +e 19. tied() is DESTROY Use of uninitialized value in concatenation (.) or string at n8.pl lin +e 21. tied() is untied $o->{'tiedScalar'} is final value tiedScalar is now untied myObj destroyed C:\Documents and Settings\Owner\Desktop>
with "$o->untiescalar();" I get
C:\Documents and Settings\Owner\Desktop>perl n8.pl TIESCALAR UNTIE DESTROY tiedScalar is now untied myObj destroyed C:\Documents and Settings\Owner\Desktop>
I am using ActivePerl 5.10.0. So whats going on here? Is this a bug in perl or some attempt perl is making at preventing recursion?

Comment on untie() and tied() and UNTIE dont work right inside FETCH with tied scalar
Select or Download Code
Re: untie() and tied() and UNTIE dont work right inside FETCH with tied scalar
by Anonyrnous Monk (Hermit) on Feb 16, 2011 at 14:45 UTC
    The problem is, that tied() doesn't work inside the FETCH method. untie() does work, but it never calls UNTIE method.  (...)

    Is this a bug in perl or some attempt perl is making at preventing recursion?

    Presumably the latter, which makes perfect sense, IMHO.  In other words, within the scope of the tied package, the scalar acts as if it was untied (as correctly reported by tied), so you can access the variable without causing infinite recursion. — You can still untie it, however.

    As for the UNTIE method not being called: if you do need to execute the code of that method, you could maybe call it directly, in addition to untie, when you're doing it from within the tied package.

Re: untie() and tied() and UNTIE dont work right inside FETCH with tied scalar
by ikegami (Pope) on Feb 16, 2011 at 14:46 UTC

    ->{'tiedScalar'} outside of FETCH:

    SV = PVMG(0x2e04558) at 0x3dce60 REFCNT = 1 FLAGS = (GMG,SMG,RMG) IV = 0 NV = 0 PV = 0 MAGIC = 0x2e4ac58 MG_VIRTUAL = &PL_vtbl_packelem MG_TYPE = PERL_MAGIC_tiedscalar(q) MG_FLAGS = 0x02 REFCOUNTED MG_OBJ = 0x26ad98 SV = IV(0x26ad90) at 0x26ad98 REFCNT = 1 FLAGS = (ROK) RV = 0x26ad20 SV = PVHV(0x25c8e0) at 0x26ad20 ...

    ->{'tiedScalar'} inside of FETCH:

    SV = PVMG(0x2e04558) at 0x3dce60 REFCNT = 2 FLAGS = () IV = 0 NV = 0 PV = 0 MAGIC = 0x2e4ac58 MG_VIRTUAL = &PL_vtbl_packelem MG_TYPE = PERL_MAGIC_tiedscalar(q) MG_FLAGS = 0x02 REFCOUNTED MG_OBJ = 0x26ad98 SV = IV(0x26ad90) at 0x26ad98 REFCNT = 1 FLAGS = (ROK) RV = 0x26ad20 SV = PVHV(0x25c8e0) at 0x26ad20 ...

    What happened to the flags? Some protection against infinite loops?

    Update: This is done by save_magic and restore_magic in mg.c. Definitely intentional. Key aspects:

    SvMAGICAL_off(sv); SvREADONLY_off(sv); if (!(SvFLAGS(sv) & (SVf_IOK|SVf_NOK|SVf_POK))) { /* No public flags are set, so promote any private flags to pu +blic. */ SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PR +IVSHIFT; }

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://888501]
Approved by Corion
Front-paged by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others browsing the Monastery: (12)
As of 2014-09-18 13:27 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    How do you remember the number of days in each month?











    Results (115 votes), past polls