Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

No DESTROY object.

by gam3 (Curate)
on Jan 22, 2010 at 12:47 UTC ( [id://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.

Replies are listed 'Best First'.
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 +";'
      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.
      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?

      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
Domain Nodelet?
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?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (5)
As of 2024-03-29 14:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found