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

I want an array of anonymous arrays, each with some data and a code ref. The coderef defaults to the identity function; return the scalar that was sent. (This gets overriden as needed.)
use strict; use Data::Dumper; my %x = map { $_ => [$_, sub {shift;}]} qw(a b c); print Dumper(\%x);
The result isn't what I expected:
$VAR1 = { 'a' => [ 'a', sub { "DUMMY" } ], 'b' => [ 'b', $VAR1->{'a'}[1] ], 'c' => [ 'c', $VAR1->{'a'}[1] ] };
Why do "b" and "c" share the same coderef as "a"? I had expected each would get a reference to their own sub.... Confused...

nop

Replies are listed 'Best First'.
Re: closure question
by chipmunk (Parson) on Feb 02, 2001 at 01:01 UTC
    Your sub isn't really a closure, because it doesn't reference any lexical variables that will go out of scope. Thus, there is no need for Perl to allocate a separate subroutine each time.

    On the other hand, if you changed your code to:

    use strict; use Data::Dumper; my %x = map { my $a; $_ => [$_, sub {$a; shift;}] } qw(a b c); print Dumper(\%x);
    then the sub becomes a closure, and you get three distinct subroutines, each one refering to a distinct instance of $a.
Re: closure question
by Fastolfe (Vicar) on Feb 02, 2001 at 01:53 UTC
    Is there any reason you need the subroutine to be separate for each element? Let perl compile it once and use the same coderef for each element if you can, as that saves on memory and work. That doesn't prevent you from overriding those definitions with another coderef if you need to.

    Also, don't be confused by the "DUMMY" bit (not that you've given any indication that you are confused -- mainly this is for the benefit of others). Data::Dumper can't deal with coderefs, so it just inserts a subroutine that is effectively a no-op, and returning "DUMMY" is as good as anything else.

      Good point. I was getting confused by the Dumper representation: I was worried that if I changed the 'a' coderef, then 'b' and 'c' would point to garbage. (Repeat often: Perl isn't C! Perl Isn't C! Perl isn't C! Hurrah.) The way I understand reference counting, the anon sub will stay around until the last reference to it goes away. The way Dumper printed it, I was incorrectly thinking that the 'a' coderef was somehow "primary", and the 'b' and 'c' refs were somehow subordinate.

      As for writing subroutines that don't seem to do much... hey, that's my login name, nop!
Re: closure question
by runrig (Abbot) on Feb 02, 2001 at 01:00 UTC
    The output from Dumper is funny, but the coderefs work for this:
    #!/usr/local/bin/perl -l -w use Data::Dumper; my @arr = map {my $var=$_; [$_, sub {$var}]} qw(a b c); print Dumper(\@arr); print &{$arr[0][1]}; print &{$arr[1][1]};
    Oh, I notice you wanted a hash, well I'm sure you can figure it out :)
    And this is probably not what you want anyway... I think I'll refrain from posting the rest of today :(