Create a gist now

Instantly share code, notes, and snippets.

What would you like to do?
perl: DESTROY called in unexpected sequence
use strict;
use warnings;
=head1 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:
mySub returned a undefined value
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
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
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;
my ($self) = @_;
package main;
sub mySub {
my $mySubGuard = $sClass->new(sub { print "shouldDestroyFirst\n" });
# Do something - any no-op will do.
# 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