Beefy Boxes and Bandwidth Generously Provided by pair Networks
There's more than one way to do things
 
PerlMonks  

when is destroy function called

by david2008 (Scribe)
on Feb 27, 2013 at 16:32 UTC ( [id://1020920]=perlquestion: print w/replies, xml ) Need Help??

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

Hi all,

This is a question regarding general knowledge of the perl language.
If i undef an object and the object has a destroy function, when is this function called ?
If i have a code

use Spreadsheet::WriteExcel; use File::Copy; # Create a new Excel workbook my $workbook = Spreadsheet::WriteExcel->new('perl.xls'); # Add a worksheet my $worksheet = $workbook->add_worksheet(); # Write a formatted and unformatted string, row and column notation. $col = $row = 0; $worksheet->write($row, $col, 'Hi Excel!', $format); undef $worksheet; undef $workbook; copy("perl.xls","perl2.xls") or die "Copy failed: $!";

The excel workbook object has a destructor which calls the close function.
Can i assume that the close function of the workbook is called before the copy call, or do i have to close the workbook explicitely?
In c++ the destructor is called right when the object goes out of scope.
In java the destructor is called when the garbage collector wants and i can not rely on it.
What happens in perl ?

Thanks,
David

Replies are listed 'Best First'.
Re: when is destroy function called
by tobyink (Canon) on Feb 27, 2013 at 16:53 UTC

    Maybe this is helpful?

    use v5.14; package Mouth { use Moo; has teeth => (is => 'ro'); sub DESTROY { say 'Mouth->DESTROY' } } package Head { use Moo; has mouth => (is => 'ro'); sub DESTROY { say 'Head->DESTROY' } } my $mouth = Mouth->new(teeth => []); my $head = Head->new(mouth => $mouth); say 'undefining $mouth'; # Note: DESTROY not called, because $head still refers to $mouth undef $mouth; say 'undefining $head'; # Now both DESTROY methods will be called undef $head;

    Compare that with the ZombieHead which allows its mouth to randomly disintegrate by using a weak reference...

    use v5.14; package Mouth { use Moo; has teeth => (is => 'ro'); sub DESTROY { say 'Mouth->DESTROY' } } package ZombieHead { use Moo; has mouth => (is => 'ro', weak_ref => 1); sub DESTROY { say 'Head->DESTROY' } } my $mouth = Mouth->new(teeth => []); my $head = ZombieHead->new(mouth => $mouth); say 'undefining $mouth'; undef $mouth; # DESTROY is called!! say 'undefining $head'; undef $head;

    References can be weakened using Scalar::Util.

    package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name

      Maybe this is helpful?

      I don't think your first example helps answer the op's question. Did the gc destroy the objects immediately after you undefined $head or did the gc merely mark them as ready for destruction, and then when the program ended the memory was released?

      Some evidence from "Intermediate Perl (2nd)", p. 257:

      To do the proper cleanup operations when Perl destroys an object, we need to know when that happens. Thankfully, Perl provides such notification upon request. We can request this notification by giving the object a DESTROY method.
      
      When the last reference to an object, say $bessie, disappears, Perl invokes that object’s DESTROY method automatically, *as if we had called it ourselves*:
      
      $bessie−>DESTROY
      
      This method call is like most other method calls: Perl starts at the class of the object and works its way up the inheritance hierarchy until it finds a suitable method. However, unlike most other method calls, there’s no error if Perl doesn’t find a suitable method.

      That suggests that DESTROY is called immediately after the reference count goes to 0--in other words the object is not merely marked for destruction with DESTROY being called at the gc's leisure.

Re: when is destroy function called
by aitap (Curate) on Feb 27, 2013 at 16:44 UTC
    As perldoc perlobj 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.
    So you can safely copy the file after the object was undefined.
    Sorry if my advice was wrong.
Re: when is destroy function called
by ggoebel (Sexton) on Feb 28, 2013 at 04:20 UTC

    Perl is reference counted. So unless you're writing XS or creating circular references, you don't need to pay much attention. However, for those times when you do... the destructor is called when the last reference is undefined.

    the following...

    package Dalek;
    sub new { return bless {}; }
    sub exterminate { return q{'exterminate'}; }
    sub obey { return q{'obey'}; }
    sub DESTROY { print "destroy\n"; }
    
    package main;
    my $obj = Dalek->new();
    print "obj is a: ", ref($obj), "\n";
    print "Where's my ", eval('$obj->obey()'), undef($obj), eval('$obj->exterminate()'), " spanner?\n";
    print $@ if $@;
    

    gives...

    > perl destroy.pl
    obj is a: Dalek
    Where's my 'obey' spanner?
    destroy
    Can't call method "exterminate" on an undefined value at (eval 2) line 1.
    

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

Re: when is destroy function called
by sundialsvc4 (Abbot) on Feb 27, 2013 at 18:29 UTC

    perldoc perlobj contains a definitive discussion both of destructors and of Perl’s garbage collector.   I think that the best way of thinking of both constructors and destructors is that they are “initialization” and “de-initialization” subroutines, respectively.   Of the two, destructors are less commonly used because they are less commonly required:   if there are no “unusual” storage-reference situations that might confuse the garbage collection algorithm, and no external resources to clean up, you often don’t need one.

    As a rule of thumb, if you do something in the object’s constructor that is peculiar to that particular object instance and that has to be un-done, then you need to worry about defining a destructor.   But if you simply allocated a big data-structure that’s associated with the object, no worries, because the reference-count of all those things will also go to zero when the object itself does.   (Any exceptions to that rule will of course require an appropriate destructor.)

    One thing that I can definitely say from very painful experience is this:   that you must never leave an ambiguous situation behind when your destructor completes.   If you “close” a socket, say, then immediately obliterate all memory of it (undef).   This is doubly true if you are indulging in fancy-pants designs involving subclasses of any sort.   Look carefully at the entire constructor and destructor sequences as your application grows.

Re: when is destroy function called
by Athanasius (Archbishop) on Feb 28, 2013 at 12:25 UTC

    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:

    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,

      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,

      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

        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

        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,

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others making s'mores by the fire in the courtyard of the Monastery: (4)
As of 2024-03-29 00:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found