Created
July 11, 2012 07:03
-
-
Save pmorch/3088551 to your computer and use it in GitHub Desktop.
perl: DESTROY called in unexpected sequence
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use strict; | |
use warnings; | |
=head1 DESTROY called in unexpected sequence | |
See http://stackoverflow.com/questions/11427281/destroy-called-in-unexpected-sequence | |
for discussion. | |
I started out noticing something odd about "Scope::Guard". If I undef | |
a "$guard" variable as the very last statement in a sub, the guard's sub gets | |
called later than I expect. If I don't undef it, or if I do something | |
(anything) after "undef $guard", it gets called when the reference goes out of | |
scope as documented. I wonder why. | |
In the following I've made my own poor-man's "Scope::Guard" ("SGuard" below) | |
just to make the example as simple as possible. You can also use "Scope::Guard" | |
and get the exact same results that are unexpected at least to me. | |
I'm expecting that the "$mySubGuard" inside "mySub()" should be destroyed first | |
and the "$scopeGuard" in the scope that calls "mySub()" should be destroyed | |
last. And so get output like: | |
shouldDestroyFirst | |
mySub returned a undefined value | |
shouldDestroyLast | |
done | |
Which I do get if I uncomment the "undef $mySubGuard" line. But instead, using | |
the snippet below, I get this output: | |
mySub returned a undefined value | |
shouldDestroyLast | |
shouldDestroyFirst | |
done | |
So from the output, it looks like the "$mySubGuard" from "mySub()" is destoyed | |
after variables local to the outer scope are destroyed. | |
Why does behavior differ just because I undef a variable that is about to go | |
out of scope anyway? And why does it matter whether something is done | |
afterwards? | |
=cut | |
my $sClass = 'SGuard'; | |
# Uncomment to use Scope::Guard instead: | |
# use Scope::Guard; $sClass = 'Scope::Guard'; | |
package SGuard; | |
sub new { | |
my ($class, $sub) = @_; | |
return bless { sub => $sub }, $class; | |
} | |
sub DESTROY { | |
my ($self) = @_; | |
$self->{sub}->(); | |
} | |
package main; | |
sub mySub { | |
my $mySubGuard = $sClass->new(sub { print "shouldDestroyFirst\n" }); | |
# Do something - any no-op will do. | |
undef; | |
# Comment out this line and it works | |
undef $mySubGuard; | |
# Or uncomment the next undef line and it works. Any statement(s) or | |
# no-ops will do but we test the return value of mySub to make sure it | |
# doesn't return a reference, so undef... | |
# undef; | |
} | |
{ | |
my $scopeGuard = $sClass->new(sub { print "shouldDestroyLast\n" }); | |
# Check that mySub returns undef to ensure the reference *did* go out | |
# of scope | |
printf "mySub returned a %sdefined value\n", | |
defined mySub() ? "" : "un"; | |
} | |
print "done\n"; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment