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

Hi

I'm a little surprised by the following behavior, I'm chaining generators, such that iterators can be combined:

my $call=0; sub generator (;$) { my $inner_iter=shift; my $dummy; $outer_iter=sub {}; # $outer_iter=sub { $inner_iter->() }; # $outer_iter=sub { $dummy++ }; $call++; print "Call Nr $call\n"; if ($inner_iter){ print $inner_iter."\n"; if ( $inner_iter eq $outer_iter) { print "ERROR !!!\n" } } return $outer_iter; } print generator generator;

I expected that the second anonymous sub $outer_iter to be different from the first, which is also present in the same scope as $inner_iter and hasn't been destroyed yet.

But that's not the case:

/usr/bin/perl -w /tmp/tst.pl Call Nr 1 Call Nr 2 CODE(0x90fa080) ERROR !!! CODE(0x90fa080)

Only uncommenting line 8 or 9 helps, such that an outer variable belongs to the closure of $outer_iter.

Call Nr 1 Call Nr 2 CODE(0x9604880) CODE(0x9623210)

Seems to be an optimization from Perl, kind of constant folding of subs which aren't closures.

So I already have a work around ...

... but out of curiosity, is there any other way to force the creation of a really different instance of a sub, even with the same body but without creating a closure?

Cheers Rolf

UPDATE: I'm still not sure if this should be considered a feature or a bug. It's not the same as with other "data" structures:
sub gen_arr { my $inner_arr=shift; print my $outer_arr=[]; return $outer_arr; } gen_arr gen_arr; #prints ARRAY(0xa179880)ARRAY(0xa179760)

Replies are listed 'Best First'.
Re: Avoiding reference of sub optimization
by JavaFan (Canon) on Mar 21, 2011 at 14:57 UTC
    UPDATE: I'm still not sure if this should be considered a feature or a bug. It's not the same as with other "data" structures:
    A subroutine isn't a data structure. Note that the same happens with other literals:
    #!/usr/bin/perl -l sub gen_arr { my $inner =shift; print my $outer = \"foo"; return $outer; } gen_arr gen_arr; __END__ SCALAR(0x9400bc4) SCALAR(0x9400bc4)
    If you really must create different addresses, use eval:
    my $outer = eval "sub {1;}"; # Different address each time.
      Just for clarity!

      It's not the literal which makes the difference but - as already suspected in the OP - the constant folding.

      #!/usr/bin/perl -l sub gen_arr { my $inner =shift; print my $outer = \"foo$inner"; # still a literal but not constant a +nymore return $outer; } gen_arr gen_arr;

      Use of uninitialized value $inner in concatenation (.) or string at /t +mp/tst2.pl line 6. SCALAR(0x912c760) SCALAR(0x912c9d0)

      Cheers Rolf

      > A subroutine isn't a data structure.

      Well obviously not in Perl, but there is a reason why I've put "data" into quotes. :)

      But thanks for the literal example, good point! ¹

      Cheers Rolf

      UPDATE:

      1) and another example of constant folding.

Re: Avoiding reference of sub optimization
by jethro (Monsignor) on Mar 21, 2011 at 14:14 UTC

    Is there any reason for this? Without a closure those two subroutines will be exactly the same and do and return the same things in all circumstances. So why should they be different?

    UPDATE to your UPDATE: An array is different since you can change values in it. But you can't edit a subroutine "in flight"

      I totally understand your point about immutable subs , but...

      > UPDATE to your UPDATE: An array is different since you can change values in it. But you can't edit a subroutine "in flight"

      Actually I'm blessing them into a dedicated class to set attributes, so subs with the same body can have different attributes. (like debug informations)

      UPDATE: And yes using subs as objects isn't frequently done in Perl ...

      Cheers Rolf

        Actually I'm blessing them into a dedicated class to set attributes, so subs with the same body can have different attributes. (like debug informations)
        Any reason why you aren't using a closure then? Which ought to give you exactly that, plus give you different references as preferred....

        Doctor, it hurts when I do this.

        I vote against Perl hiding the fact that two code references are identical and increasing memory usage to do so in order to enable a dubious use of "code reference as object".

        - tye