Beefy Boxes and Bandwidth Generously Provided by pair Networks
Perl-Sensitive Sunglasses
 
PerlMonks  

Re: when is destroy function called

by Athanasius (Monsignor)
on Feb 28, 2013 at 12:25 UTC ( #1021047=note: print w/ replies, xml ) Need Help??


in reply to when is destroy function called

The documentation in perlobj, as quoted by aitap, says:

When the last reference to an object goes away, the object is destroyed. If you only have one reference to an object stored in a lexical scalar, the object is destroyed when that scalar goes out of scope.

This can be read in two ways:

  1. The object’s DESTROY method (if any) is called immediately when its reference count drops to zero.
  2. When an object’s reference count drops to zero, it is scheduled for destruction, and the DESTROY method (if any) is called by the Perl runtime at the first opportunity.

The consensus in this thread seems to be that interpretation (1) is correct, but ggoebel has in fact provided a counterexample — notwithstanding the fact that ggoebel himself says:

Note that the object is destroyed before the print statement in the destructor is flushed to STDOUT

But I don’t believe that flushing the output filehandle plays any part here. Adding $| = 1; at the top of the code makes no difference to the output. My understanding is that in ggoebel’s example what happens is this:

  • When undef($obj) executes, the value of $obj is set to undef;
  • the object’s reference count is decremented to zero;
  • the object is scheduled for destruction, but not yet destroyed;
  • the print statement completes;
  • then and only then the object’s DESTROY method is called.

That is, the error warning message indicates only that $obj is undef, not that the object to which $obj formerly pointed has been destroyed.

As evidence I offer the following adaptation of ggoebel ’s example, enhanced to give the object a resource which it modifies in its DESTROY method:

#! perl use strict; use warnings; $| = 1; #--------------------------------------------------------------------- +--------- package Phaser; sub new { my ($class, $name) = @_; my $self = {}; $self->{name} = $name; return bless $self, $class; } #--------------------------------------------------------------------- +--------- package Dalek; sub new { my ($class, $phaser_ref) = @_; my $self = {}; $self->{phaser} = $phaser_ref; return bless $self, $class; } sub exterminate { return 'Firing phaser ' . $_[0]->{phaser}->{name} . "\n"; } sub obey { return 'obey'; } sub DESTROY { my ($self) = @_; print 'DESTROYing a Dalek (phaser is ', $self->{phaser}->{name}, " +)\n"; $self->{phaser}->{name} = 'Obliterator'; } #--------------------------------------------------------------------- +--------- package main; my $phaser = Phaser->new('Exterminator'); my $enemy = Dalek ->new($phaser); print 'My enemy is a ', ref $enemy, ' with a phaser named ', $phaser->{name}, "\n"; print $enemy->exterminate(); print 'My enemy must ', $enemy->obey(), undef($enemy), '. His phaser is named ', $phaser->{name}, eval('$enemy->exterminate()'), ". Bye!\n"; print $@ if $@; print 'The phaser is named ', $phaser->{name}, "\n";

Output:

16:59 >perl 552_SoPW.pl My enemy is a Dalek with a phaser named Exterminator Firing phaser Exterminator Use of uninitialized value in print at 552_SoPW.pl line 67. My enemy must obey. His phaser is named Exterminator. Bye! DESTROYing a Dalek (phaser is Exterminator) Can't call method "exterminate" on an undefined value at (eval 1) line + 1. The phaser is named Obliterator 16:59 >

As can be seen by the change of phaser name from “Exterminator” to “Obliterator”, the DESTROY method is not called until immediately after the print statement completes.

I conclude that the documentation should be read according to the second interpretation. If this were C++, we could refer to an account of “sequence points” for a precise statement of when the DESTROY method is called. As it is, the following seems like a good rule of thumb for destructors in Perl:

When an object’s reference count falls to zero, its DESTROY method will be called immediately upon completion of the statement (not expression) in which the reference count is decremented.

In some (probably rare) cases, this might be an important distinction to keep in mind.

Hope that helps,

Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,


Comment on Re: when is destroy function called
Select or Download Code
Re^2: when is destroy function called
by 7stud (Deacon) on Mar 02, 2013 at 07:05 UTC

    That is, the error message indicates only that $obj is undef, not that the object to which $obj formerly pointed has been destroyed.

    First, a variable has no memory of what it was. It just knows what it is.

    Secondly, I'm baffled by your explanation of the example's output. It seems clear to me that the output from the DESTROY method comes before the error message, yet you conclude that DESTROY isn't called until after the error message.

    I have to admit I have no idea what the example is supposed to demonstrate with all the eval()'s, strange names, and unintelligible (English?) output. Here is my example (which seems to prove your conclusion):

    use strict; use warnings; use 5.010; $| = 1; { package Dog; sub new { return bless {}; } sub bark { say 'Bow wow!' } sub DESTROY { print "destroy\n"; } } my $dog = Dog->new(); print 'hello', $dog->bark(), undef $dog, $dog->bark(), 'world', ; --output:-- Bow wow! Can't call method "bark" on an undefined value at 2.pl line 17. destroy

      Sorry, my bad. I added use warnings to my copy of ggoebel’s script; forgot that it wasn’t in the original; and then compounded the confusion by referring to the warning which results as an “error’. The warning in question is:

      Use of uninitialized value in print at...

      which comes from the inclusion of undef($obj) in the arguments to the print statement.

      The evals are there to allow the print statement to complete in spite of the error (exception) which results from the attempt to call a method on an undefined object. That error is:

      Can't call method "exterminate" on an undefined value at (eval 2) line + 1.

      which in the original example was captured by the eval and printed by the statement print $@ if $@;.

      I agree that your example “seems to prove” my conclusion; but I wanted to be sure. Hence my provision of an additional resource which is altered within the DESTROY method. Adapting your example:

      #! perl use strict; use warnings; use 5.010; $| = 1; my $num = 42; { package Dog; sub new { return bless {}; } sub bark { say 'Bow wow!'; } sub DESTROY { print "destroy\n"; ++$num; } } my $dog = Dog->new(); print 'hello ', $dog->bark(), undef $dog, eval('$dog->bark()'), "|$num|", "world\n"; print $num;

      Output:

      18:02 >perl 552_SoPW.pl Bow wow! Use of uninitialized value in print at 552_SoPW.pl line 31. hello 1|42|world destroy 43 18:02 >

      which shows that $num is incremented only after the print statement completes, and not at the point where the reference count of $dog falls to zero. (Note that the “1” in the output comes from the say statement in Dog::bark, which returns true on success.)

      Hope that helps,

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      Secondly, I'm baffled ...

      Nope, obey is printed before DESTROY. use the debugger, or just Devel::Trace, if you can't follow the text

      $ perl -d:Trace dalek >> dalek:4: $| = 1; >> dalek:48: my $phaser = Phaser->new('Exterminator'); >> dalek:11: my ($class, $name) = @_; >> dalek:12: my $self = {}; >> dalek:13: $self->{name} = $name; >> dalek:14: return bless $self, $class; >> dalek:49: my $enemy = Dalek ->new($phaser); >> dalek:22: my ($class, $phaser_ref) = @_; >> dalek:23: my $self = {}; >> dalek:24: $self->{phaser} = $phaser_ref; >> dalek:25: return bless $self, $class; >> dalek:51: print 'My enemy is a ', ref $enemy, My enemy is a Dalek with a phaser named Exterminator >> dalek:53: print $enemy->exterminate(); >> dalek:30: return 'Firing phaser ' . $_[0]->{phaser}->{name} . " +\n"; Firing phaser Exterminator >> dalek:55: print 'My enemy must ', $enemy->obey(), >> dalek:35: return 'obey'; >> (eval 1)[dalek:55]:1: $enemy->exterminate() Use of uninitialized value in print at dalek line 55. My enemy must obey. His phaser is named Exterminator. Bye! >> dalek:40: my ($self) = @_; >> dalek:41: print 'DESTROYing a Dalek (phaser is ', $self->{phase +r}->{name}, ")\n"; DESTROYing a Dalek (phaser is Exterminator) >> dalek:42: $self->{phaser}->{name} = 'Obliterator'; >> dalek:60: print $@ if $@; Can't call method "exterminate" on an undefined value at (eval 1)[dale +k:55] line 1. >> dalek:62: print 'The phaser is named ', $phaser->{name}, "\n"; The phaser is named Obliterator

      unintelligible (English?)

      Its perfectly intelligible , its just a bit of fiction

      Here is my example (which seems to prove your conclusion)

      It doesn't really, the program dies before print prints anything -- it short circuits, failing to prove that order of cleanup/DESTROY isn't immediate

      On a related note about global destruction order, see sub DESTROY: Strange ordering of object destruction (global destruction order not guaranteed

Re^2: when is destroy function called
by roboticus (Canon) on Mar 02, 2013 at 15:43 UTC

    Athanasius:

    I lean towards the first reading. I think the reason that the destroy method executes after print completes is because a reference to the object is placed on the stack, and the reference count goes to zero when the parameters are cleared from the stack.

    Calling destroy immediately is simpler than maintaining a to-do list for later processing. If I were to write perl, I'd choose the simpler method. (Of course, I can't offer any evidence either way--it's just my gut feeling.)

    ...roboticus

    When your only tool is a hammer, all problems look like your thumb.

      roboticus:

      I think the reason that the destroy method executes after print completes is because a reference to the object is placed on the stack, and the reference count goes to zero when the parameters are cleared from the stack.

      So the idea is that DESTROY is called immediately when the reference count falls to zero, but that the decrementing of the reference count does not occur immediately upon the call to undef? That sounds reasonable, but I’m not sure which stack is meant. It can’t be the subroutine’s parameter list:

      #! perl use strict; use warnings; { package Foo; sub new { return bless {}; } sub DESTROY { print "Foo::DESTROY\n"; } } my $foo = Foo->new(); bar($foo); print "Back in main\n"; sub bar { print "Begin bar()\n"; undef $_[0]; print "End bar()\n"; }

      Output:

      3:14 >perl 556_SoPW.pl Begin bar() Foo::DESTROY End bar() Back in main 3:18 >

      Can you clarify what you mean by “a reference to the object is placed on the stack”?

      Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

        Athanasius:

        Yeah, I could've been more clear...

        I meant that when setting up the print statement:

        print 'My enemy must ', $enemy->obey(), undef($enemy), '. His phaser is named ', $phaser->{name}, eval('$enemy->exterminate()'), ". Bye!\n";

        that I suspect that perl may be putting a reference to the thing $enemy refers to on the stack for the purpose of calling the obey() method (and possibly for the undef thing, too). So that we'd have something like this:

        *** Before print statement *** $enemy------------------------->Dalek:{phaser=> + } (ref=1) | +---------------+ v $phaser------------------------>Phaser:{name=> + } (ref=2) | +--------------+ v 'Exterminator' (ref=1) argument stack: -empty- *** After print setup, before print executes *** $enemy------------------------->Dalek:{phaser=> + } (ref=2)<-+ | | +---------------+ | v | $phaser------------------------>Phaser:{name=> + (ref=2) | | | +--------------+ | v | 'Exterminator' (ref=2) | ^ | +--------------+ | argument stack: '. Bye!\n' | | eval('$enemy->exterminate()' | | ref---------------------------+ | '. His phaser is named ' | undef($enemy) | obey()<-ref---------------------------------+ 'My enemy must '

        At this point, I'm guessing the stack contains a reference to the Dalek that $enemy also points to, so it can call the obey method.

        *** Executing through print, just after undef step *** $enemy--->undef Dalek:{phaser=> + } (ref=1)<-+ | | +---------------+ | v | $phaser------------------------>Phaser:{name=> + (ref=2) | | | +--------------+ | v | 'Exterminator' (ref=2) | ^ | +--------------+ | argument stack: '. Bye!\n' | | eval('$enemy->exterminate()' | | ref---------------------------+ | '. His phaser is named ' | undef($enemy) | obey()<-ref---------------------------------+ 'My enemy must '

        Here, we've already executed the obey() method so the string gets printed, and we've just executed undef, so the link between $enemy and the Dalek is now broken. But the argument stack for print still holds the reference to the Dalek.

        *** Print just finished, now removing items from stack ... *** $enemy--->undef Dalek:{phaser=> + } (ref=1)<-+ | | +---------------+ | v | $phaser------------------------>Phaser:{name=> + (ref=2) | | | +--------------+ | v | 'Exterminator' (ref=1) | | argument stack: obey()<-ref---------------------------------+ 'My enemy must '

        Most of the argument stack for the print statement is gone, the next item to go is the reference of interest. (Note: the reference count to the 'Exterminaor' string has already dropped back to 1.) So perl dutifully reduces the references count for the item on the stack, and notices the count went to 0:

        $enemy--->undef Dalek:{phaser=> + } (ref=0)<-+ | | +---------------+ | v | $phaser------------------------>Phaser:{name=> + (ref=2) | | | +--------------+ | v | 'Exterminator' (ref=1) | | argument stack: obey()<-ref---------------------------------+ 'My enemy must '

        ...at which point it tells the Dalek to go DESTROY itself. While it destroys itself, it discards the reference to the Phaser (reducing its reference count):

        $enemy--->undef Dalek:{phaser=> } (ref=0)<-+ | $phaser------------------------>Phaser:{name=> + (ref=1) | | | +--------------+ | v | 'Exterminator' (ref=1) | | argument stack: obey()<-ref---------------------------------+ 'My enemy must '

        The Phaser still has a reference, so it's going to stick around. When the DESTROY method returns, perl then frees the Dalek memory, and continues to remove items from the argument stack:

        $enemy--->undef {FREE MEMORY } $phaser------------------------>Phaser:{name=>'Exterminator'} (ref=1) argument stack: 'My enemy must '

        I guess I should've put a reference count on the 'Exterminator' string, as well, but I didn't think of it until after I drew all of that, and I'm not quite ambitious enough to fix that oversight.

        Here's a bit of code I came up with in an attempt to lend some weight to my theory. It's not proof, as I can't think of a way to examine the variables in the middle of stack cleanup (short of running perl under gdb):

        The results are a bit tedious to read through, though:

        Update: I went ahead and updated the diagram to show the reference counts for the 'Exterminated' string as well. It make the node a bit longer, but I think it helps illustrate things. I also added a couple readmore tags to make a long post somewhat shorter.

        ...roboticus

        When your only tool is a hammer, all problems look like your thumb.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others having an uproarious good time at the Monastery: (5)
As of 2014-09-02 02:01 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    My favorite cookbook is:










    Results (18 votes), past polls