http://www.perlmonks.org?node_id=989646

tqisjim has asked for the wisdom of the Perl Monks concerning the following question:

I'm running an older version: This is perl, v5.8.9 built for i686-linux Here's sample script:
use Switch ; $perldata = bless { hello => 'world' }, 'superman' ; # $perldata = { hello => 'world' } ; sub test { my $o = shift ; warn $o ; my $m = bless { perldata => $o }, 'TQIS::test' ; return $m ; } sub TQIS::test::DESTROY { my $self = shift ; warn $self->{perldata} ; } $a = test( $perldata ) ; $b = test( $perldata ) ; $c = test( $perldata ) ;
Here's what happens when I run the script:
$ perl /tmp/err.pl superman=HASH(0x9b0d18c) at /tmp/err.pl line 8. superman=HASH(0x9b0d18c) at /tmp/err.pl line 8. superman=HASH(0x9b0d18c) at /tmp/err.pl line 8. superman=HASH(0x9b0d18c) at /tmp/err.pl line 15 during global destruct +ion. superman=HASH(0x9b0d18c) at /tmp/err.pl line 15 during global destruct +ion. Warning: something's wrong at /tmp/err.pl line 15 during global destru +ction. $
If I comment out the 'use Switch' statement, the superman reference prints out correctly 3 times on line 15. Incidentally, I also get the correct result of the variable perldata is not blessed. I'm guessing this is a bug. Does anybody else experience the same thing? -Jim

Replies are listed 'Best First'.
Re: use Switch wierdness
by runrig (Abbot) on Aug 24, 2012 at 22:28 UTC
    Switch is a bug (this statement is an exaggeration, but see Categorized Damian Modules...maybe 'Switch is a bug waiting to happen'??). Don't use it in production. Even if it was (mistakenly) once a core library. (if you're not using it or considering using it for any serious purpose and just experimenting, please state that in your post...sorry and move along).

      It's not just the Switch module that breaks this. Other modules seem to have the same effect. Can someone else run this code and confirm if they have the same problem?

      use DBD::mysql ; $perldata = bless { hello => 'world' }, 'superman' ; # $perldata = { hello => 'world' } ; sub test { my $o = shift ; warn $o ; my $m = bless { perldata => $o }, 'TQIS::test' ; return $m ; } sub TQIS::test::DESTROY { my $self = shift ; warn $self->{perldata} ; } $a = test( $perldata ) ; $b = test( $perldata ) ; $c = test( $perldata ) ;
Re: use Switch wierdness
by GrandFather (Saint) on Aug 25, 2012 at 02:36 UTC

    Using lexical variables or explicitly releasing references seems to fix the problem which suggests it's related to destruction order of package variables. Consider:

    $perldata = bless {hello => 'world'}, 'superman'; $bar = test($perldata); $baz = test($perldata); my $foo = test($perldata); $baz = undef; sub test { my $o = shift; print "test: $o\n"; my $m = bless {perldata => $o}, 'TQIS::test'; return $m; } sub TQIS::test::DESTROY { my $self = shift; warn $self->{perldata}; }

    Prints:

    superman=HASH(0x182b3dc) at noname2.pl line 18. test: superman=HASH(0x182b3dc) superman=HASH(0x182b3dc) at noname2.pl line 18. Warning: something's wrong at noname2.pl line 18 during global destruc +tion. test: superman=HASH(0x182b3dc) test: superman=HASH(0x182b3dc)

    Note that the "Warning: something's wrong at " text seems to get clobbered depending on things like the specific order if the ... = test lines!

    True laziness is hard work
Re: use Switch wierdness
by Anonymous Monk on Aug 25, 2012 at 07:08 UTC

    I'm guessing this is a bug.

    It is a known behaviour, Perl's "global destruction" phase doesn't obey reference counts, and the order of destruction isn't guaranteed , so $perldata gets destroyed before $c/$b,

    The solution to this kind of thing is to arrange for global objects to get destroyed before and to use weak references

    use DBI; $perldata = bless { hello => 'world' }, 'superman' ; @ARGV and $perldata = { hello => 'world' } ; sub test { my( $o, $v ) = @_; my $m = bless { v => $v, perldata => $o }, 'TQIS::test' ; warn "$m $$m{v}"; return $m ; } sub TQIS::test::DESTROY { my $self = shift ; warn "$self $$self{v} => $$self{perldata} "; } $a = test( $perldata , 'a') ; $b = test( $perldata , 'b' ) ; $c = test( $perldata , 'c' ) ; __END__ $ perl junk TQIS::test=HASH(0x3f8b5c) a at junk line 9. TQIS::test=HASH(0x99a88c) b at junk line 9. TQIS::test=HASH(0xa57854) c at junk line 9. TQIS::test=HASH(0xa57854) c => at junk line 15 during global destruc +tion. TQIS::test=HASH(0x99a88c) b => at junk line 15 during global destruc +tion. TQIS::test=HASH(0x3f8b5c) a => superman=HASH(0x3f8a7c) at junk line 1 +5 during global destruction. $ perl junk --nobless TQIS::test=HASH(0x99a43c) a at junk line 9. TQIS::test=HASH(0x99a97c) b at junk line 9. TQIS::test=HASH(0xa576a4) c at junk line 9. TQIS::test=HASH(0xa576a4) c => HASH(0x3f8d04) at junk line 15 during +global destruction. TQIS::test=HASH(0x99a97c) b => HASH(0x3f8d04) at junk line 15 during +global destruction. TQIS::test=HASH(0x99a43c) a => HASH(0x3f8d04) at junk line 15 during +global destruction.

    See also Re: sub DESTROY: Strange ordering of object destruction

      Muddling along with my project, I took two approaches:

      1. I took out a circular link, which was necessary anyways, to avoid global destruction.
      2. I'm no longer blessing $perldata- I'm oldschool enough to have learned on Perl4 anyways.

      If I understand your explanation correctly, using a blessed or unblessed version of $perldata may only re-arrange an indeterminate destruction order, and therefore not a reliable solution. But then you took the same approach with your command line switch... Can you explain?

      I also tested with the following code:

      superman::DESTROY { warn "Blasted Kryptonite" ; }

      Based on my observation, the superman object is destroyed when expected, after all the referencing objects. It's not that the references point to a destroyed object so much as the references themselves are getting clobbered. I'm probably digging too deep- If I have to think this hard in Perl, I must be taking the wrong approach.

      Finally, thanks for the heads up about weak references. I was not aware of them.

(OT) Re: use Switch wierdness
by Athanasius (Archbishop) on Aug 25, 2012 at 08:07 UTC

    The title of this thread reminded me of a quote from the Camel Book (4th Edition, “Lookaround Assertions”, p. 249):

    (?<!PATTERN) (negative lookbehind)
    When the Engine encounters (?<! PATTERN), it looks backward in the string to ensure that PATTERN did not occur.

    Let’s go for a really simple example this time. How about the easy version of that old spelling rule, “I before E except after C”? In Perl, you spell it:
    s/(?<!c)ei/ie/g
    You’ll have to weigh for yourself whether you want to handle any of the exceptions. (For example, “weird” is spelled weird, especially when you spell it “wierd”.)

    SCNR ;-)

    Athanasius <°(((><contra mundum

      tuoche!