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

if(my) scope

by oha (Friar)
on Apr 16, 2009 at 10:33 UTC ( #757929=perlquestion: print w/ replies, xml ) Need Help??
oha has asked for the wisdom of the Perl Monks concerning the following question:

Hi, I got a strange issue I would like to share, in the following code:
package H; sub DESTROY { print "DESTROY\n"; } sub new { my $class = shift; bless {}, $class; } { if(my $h = H->new()) { print "IN\n"; } print "\$h out of scope\n"; } print "why now?\n"; _____ IN $h out of scope DESTROY why now?
why DESTROY is called after the outer { } ? after the if() block $h is no longer reachable, so why still holds a reference to the blessed instance?

Oha

edit: This is perl, v5.10.0 built for i486-linux-gnu-thread-multi

Comment on if(my) scope
Download Code
Re: if(my) scope
by dada (Chaplain) on Apr 16, 2009 at 10:49 UTC
    perltoot says:
    Perl's notion of the right time to call a destructor is not well-defined currently, which is why your destructors should not rely on when they are called.
    so the answer is: none of your business :-)

    cheers,
    Aldo

    King of Laziness, Wizard of Impatience, Lord of Hubris

      Just to expand on the above:

      In garbage-collected languages it is generally a bad idea to worry about exactly when a specific piece of data is garbage collected. It will happen at the runtime's convenience, no sooner, and no later. Doing immediate collection is generally more work (at runtime) than it is ever going to be worth.

      So, expect that timing to change on different boxes, runs, and if you recompile. The only thing you are in good shape to be sure of it that it will happen after the variable has gone out of scope.

        Expanding a bit further.

        That comment only applies to mark-and-sweep type garbage collection. As a general rule, Perl's reference-counted garbage collection is deterministic and mostly handles as you would expect. (Present case excepted, of course.)

        Personally, I regret the loss of a defined, consistent object lifetime caused by using mark-and-sweep. Having the lifetime of a object determine the timing of events is quite useful. It's one of the reasons I prefer Perl and C++ to Java.

        G. Wade
Re: if(my) scope
by targetsmart (Curate) on Apr 16, 2009 at 10:50 UTC
    the phenomenon you noted is absolutly normal, if the reference count of $h goes to zero, it is automatically freed by perl, since it is associated with a object, the DESTROY method in the class will be called.
    see perltoot Destructors
    UPDATE
    I generally talked about the way the DESTROY is called, but this is new to me, pardon if it caused some confusion.

    Vivek
    -- In accordance with the prarabdha of each, the One whose function it is to ordain makes each to act. What will not happen will never happen, whatever effort one may put forth. And what will happen will not fail to happen, however much one may seek to prevent it. This is certain. The part of wisdom therefore is to stay quiet.
      That wasn't the question. The question was why DESTROY is called after the outer { } ? after the if() block $h is no longer reachable, so why still holds a reference to the blessed instance?
        IMO the $h is visible entirely to the outer {} rather than 'if' block. I have to check the docs.

        UPDATE
        thanks to citromatik, but I know that the $h should get deallocated immediately after the 'if' block, but the example shown has confused me a bit, so I just coined my guess!. that is why i put 'In my opinion'. This is kind of learning about DESTROY and I will take it gleefully.

        Vivek
        -- In accordance with the prarabdha of each, the One whose function it is to ordain makes each to act. What will not happen will never happen, whatever effort one may put forth. And what will happen will not fail to happen, however much one may seek to prevent it. This is certain. The part of wisdom therefore is to stay quiet.

      f the reference count of $h goes to zero, it is automatically freed by perl,

      But why does it go to zero where it does.

      package H; sub DESTROY { print "DESTROY\n"; } sub new { my $class = shift; bless {}, $class; } { print \$h, "\n"; if(my $h = H->new()) { print \$h, "\n"; } print \$h, "\n"; # <- This references the package var # and would cause a strict error. # Object is no longer accessible. print "why now?\n"; } # <- The object is only destroyed here.
      SCALAR(0x1829aac) REF(0x1829abc) SCALAR(0x1829aac) why now? DESTROY
Re: if(my) scope
by ikegami (Pope) on Apr 16, 2009 at 13:49 UTC

    if is implemented in terms of and, and neither creates a scope at run-time (i.e. they don't call ENTER+LEAVE). That means they don't affect the life (refcount) of variables.

    if only affects the visibility of the variable, a compile-time effect.

    yuck!

    Update: Just to be clear, I'm talking specifically about the condition expression, not the body of the if.

      Although I am sure you are right, how come:
      use strict; use warnings; use Devel::Peek; my $true = 1; my $ref; if ($true) { my $fred = 42; $ref = \$fred; } print Dump($$ref);
      Gives:
      SV = IV(0x3b2e0) at 0x3b2e4 REFCNT = 1 FLAGS = (PADMY,IOK,pIOK) IV = 42
      A reference count of 1, not 2?
        You changed
        if (my $var) { ... }
        to
        if (...) { my $var; ... }
        use strict; use warnings; use Devel::Peek; my $ref; if ((my $fred = 42), 1) { $ref = \$fred; Dump($$ref); } Dump($$ref);
        SV = IV(0x816a5cc) at 0x814f684 REFCNT = 2 FLAGS = (PADBUSY,PADMY,IOK,pIOK) IV = 42 SV = IV(0x816a5cc) at 0x814f684 REFCNT = 2 FLAGS = (PADBUSY,PADMY,IOK,pIOK) IV = 42

        A scope is created for if's curlies, but only a compile-time scope is created for the condition expression.

        Btw, note the proper usage of Dump.

      i just realized that:
      open my $fh, '<', $file or die;
      so i'm asking myself if the possibility to setup a scope variable inside the argument of a function call is extended to _if_ statements too?

        This is fine:

        if (open(my $fh, '<', $qfn)) { ...read from $fh... } # $fh is out of reach here

        Perl doesn't care where the my is to the point that it allows the following (even though the behaviour is officially undefined):

        my $fh if ...;

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (10)
As of 2014-09-01 14:58 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite cookbook is:










    Results (13 votes), past polls