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):

#!/usr/bin/perl use Data::Dumper; use Devel::Peek; { package Foo; sub new { my $class = shift; my $val = shift; return bless { thing=>$val }; } sub val { my $self = shift; return "val: " . (++$self->{theVal}); } sub DESTROY { print "destroyed at ", ${shift}->{theVal}, "\n"; } } my $b = [ ]; my $t = Foo->new($b); print "--- before print ---\n"; Dump($b); Dump($t); print "--- Do the print ---\n"; print $t->val(), Dump($b), Dump($t), undef($t), Dump($b), Dump($t), ".\n"; print "--- after print ---\n"; Dump($b); Dump($t);

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

$ perl ex_destructo.pl --- before print --- SV = RV(0x8c650b4) at 0x8c650a8 REFCNT = 1 FLAGS = (PADMY,ROK) RV = 0x8c47818 SV = PVAV(0x8c4886c) at 0x8c47818 REFCNT = 2 FLAGS = () ARRAY = 0x0 FILL = -1 MAX = -1 ARYLEN = 0x0 FLAGS = (REAL) SV = RV(0x8c650a4) at 0x8c65098 REFCNT = 1 FLAGS = (PADMY,ROK) RV = 0x8c476f8 SV = PVHV(0x8c4fa64) at 0x8c476f8 REFCNT = 1 FLAGS = (OBJECT,SHAREKEYS) STASH = 0x8c650c8 "Foo" ARRAY = 0x8c719d0 (0:7, 1:1) hash quality = 100.0% KEYS = 1 FILL = 1 MAX = 7 RITER = -1 EITER = 0x0 Elt "thing" HASH = 0x20b61f7d SV = RV(0x8c65054) at 0x8c65048 REFCNT = 1 FLAGS = (ROK) RV = 0x8c47818 SV = PVAV(0x8c4886c) at 0x8c47818 REFCNT = 2 FLAGS = () ARRAY = 0x0 FILL = -1 MAX = -1 ARYLEN = 0x0 FLAGS = (REAL) --- Do the print --- SV = RV(0x8c650b4) at 0x8c650a8 REFCNT = 1 FLAGS = (PADMY,ROK) RV = 0x8c47818 SV = PVAV(0x8c4886c) at 0x8c47818 REFCNT = 2 FLAGS = () ARRAY = 0x0 FILL = -1 MAX = -1 ARYLEN = 0x0 FLAGS = (REAL) SV = RV(0x8c650a4) at 0x8c65098 REFCNT = 1 FLAGS = (PADMY,ROK) RV = 0x8c476f8 SV = PVHV(0x8c4fa64) at 0x8c476f8 REFCNT = 1 FLAGS = (OBJECT,OOK,SHAREKEYS) STASH = 0x8c650c8 "Foo" ARRAY = 0x8c6b8d0 (0:6, 1:2) hash quality = 125.0% KEYS = 2 FILL = 2 MAX = 7 RITER = -1 EITER = 0x0 Elt "theVal" HASH = 0x90484e39 SV = PVIV(0x8c5b04c) at 0x8cd6348 REFCNT = 1 FLAGS = (IOK,POK,pIOK,pPOK) IV = 1 PV = 0x8cd17e0 "1"\0 CUR = 1 LEN = 4 Elt "thing" HASH = 0x20b61f7d SV = RV(0x8c65054) at 0x8c65048 REFCNT = 1 FLAGS = (ROK) RV = 0x8c47818 SV = PVAV(0x8c4886c) at 0x8c47818 REFCNT = 2 FLAGS = () ARRAY = 0x0 FILL = -1 MAX = -1 ARYLEN = 0x0 FLAGS = (REAL) SV = RV(0x8c650b4) at 0x8c650a8 REFCNT = 1 FLAGS = (PADMY,ROK) RV = 0x8c47818 SV = PVAV(0x8c4886c) at 0x8c47818 REFCNT = 2 FLAGS = () ARRAY = 0x0 FILL = -1 MAX = -1 ARYLEN = 0x0 FLAGS = (REAL) SV = RV(0x8c650a4) at 0x8c65098 REFCNT = 1 FLAGS = (PADMY) val: 1. destroyed at --- after print --- SV = RV(0x8c650b4) at 0x8c650a8 REFCNT = 1 FLAGS = (PADMY,ROK) RV = 0x8c47818 SV = PVAV(0x8c4886c) at 0x8c47818 REFCNT = 1 FLAGS = () ARRAY = 0x0 FILL = -1 MAX = -1 ARYLEN = 0x0 FLAGS = (REAL) SV = RV(0x8c650a4) at 0x8c65098 REFCNT = 1 FLAGS = (PADMY)

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.


In reply to Re^4: when is destroy function called by roboticus
in thread when is destroy function called by david2008

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.