Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?
 
PerlMonks  

No DESTROY object.

by gam3 (Curate)
on Jan 22, 2010 at 12:47 UTC ( #818955=perlquestion: print w/ replies, xml ) Need Help??
gam3 has asked for the wisdom of the Perl Monks concerning the following question:

I am wondering why it is that
bless(sub {}, 'Foo');
never calls Foo->DESTROY.

And is this a well known feature of Perl OO?

perl -e '{package Foo; sub DESTROY { print "d\n"; } bless( {}, 'Foo'); +}' # d perl -e '{package Foo; sub DESTROY { print "d\n"; } bless(sub {}, 'Foo +');} # no d
-- gam3
A picture is worth a thousand words, but takes 200K.

Comment on No DESTROY object.
Select or Download Code
Re: No DESTROY object.
by ambrus (Abbot) on Jan 22, 2010 at 13:31 UTC

    sub {} does not refer to any lexical variables, so it is optimized to always return a reference to the same sub, instead of creating subs every time. Thus, that sub is never destroyed. For example, see that this prints the same address twice.

    perl -we 'sub f { sub { } }; $x = f(); $y = f(); warn "$x $y";'

    In comparision, if you get a reference with an array or hash constructor [] or {}, or with a lexical variable like do {\my $t} or do {\my @a}, you always get a fresh one because arrays and hashes are mutable.

    Update: sorry, originally I posted the wrong example code, the one that shows when the sub does refer to a lexical variable, so the two calls to f returned subs that referred to two different variables, thus, the addresses were different. It's now corrected above, below is that old code.

    perl -we 'sub f { my $t; sub { $t } }; $x = f(); $y = f(); warn "$x $y +";'
      For example, see that this prints the same address twice.

      No, it does not, at least not in perl v5.10.0:

      perl -we 'sub f { my $t; sub { $t } }; $x = f(); $y = f(); warn "$x $y +";' CODE(0x82998c4) CODE(0x8299964) at -e line 1.

      Has perl become smarter?

      That prints two different addresses. But since it's a sub that does refer to a lexical variable, it neither proves, nor disproves your claim about optimization.

      But note this:

      $ perl5.10.1 -we 'sub f { our $t; sub { $t } }; $x = f(); $y = f(); wa +rn "$x $y";' CODE(0x95ca930) CODE(0x95ca930) at -e line 1.
      Same address. But not so in 5.8.9
      $ perl5.8.9 -we 'sub f { our $t; sub { $t } }; $x = f(); $y = f(); war +n "$x $y";' CODE(0x867218c) CODE(0x8672258) at -e line 1.
      There are 2 problems with your argument that jump out at me.
      1. first - DESTROY should still get called even if only once.
      2. second sub { $bob } does not get DESTROYed either and it certainly not immutable.
      package Foo; sub print { print "@_\n"; } sub DESTROY { print "@_ DESTROY\n"; } our $bob = "x\n"; my $x = bless(sub {$bob}, 'Foo'); $x->print('$bob'); print $x->(); $bob = "y\n"; print $x->(); $bob = undef; __END__ Foo=CODE(0xe8a278) $bob x y
      -- gam3
      A picture is worth a thousand words, but takes 200K.

        For your second question, if you replace our $bob to my $bob, then the DESTROY does get called. This way, perl knows that $bob is a global so it optimizes the sub constructor to a constant again.

Re: No DESTROY object.
by WizardOfUz (Friar) on Jan 22, 2010 at 14:52 UTC

    This would work as intended:

    use strict; use warnings; package Foo; sub new { my $class = shift; return bless( eval 'sub { print "Hello!\n" }', $class ); } sub DESTROY { print "DESTROYing $_[0]\n"; return; } package main; my $object = Foo->new; print "Created $object\n"; $object->(); undef $object; print "Done.\n";
    # Created Foo=CODE(0x82cafec) # Hello! # DESTROYing Foo=CODE(0x82cafec) # Done.

    Or use closures:

    sub new { my $class = shift; my $string = "Hello!\n"; return bless( sub { print $string }, $class ); }
      UPDATE: Nevermind.

      An easier fix is

      bless(\sub {}, 'Foo');
      I don't want to fix the problem, I only want to understand it.
      -- gam3
      A picture is worth a thousand words, but takes 200K.

        Errr ... no, it is not:

        perl -we 'bless( \sub {}, "Foo" )->();' Not a CODE reference at -e line 1.
        Because:
        perl -we 'print bless( \sub {}, "Foo" ) . "\n";' Foo=REF(0x82998c4)

        Update: To answer your question: What seems to be happening is that perl inlines the subroutine. See:

        use strict; use warnings; package Foo; sub new { my $class = shift; return bless( sub { print "Hello\n" }, $class ); } sub DESTROY { print "DESTROYing $_[0]\n"; return; } package main; my $object = Foo->new; print "Created $object\n"; undef $object; print "Ha! Ha! Still there!\n"; { no strict 'refs'; my $symbol_table = \%{'Foo::'}; delete $symbol_table->{'new'}; } print "Done.\n";
        # Created Foo=CODE(0x82b682c) # Ha! Ha! Still there! # DESTROYing Foo=CODE(0x82b682c) # Done.

Log In?
Username:
Password:

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

How do I use this? | Other CB clients
Other Users?
Others musing on the Monastery: (8)
As of 2014-10-21 06:08 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    For retirement, I am banking on:










    Results (96 votes), past polls