I disagree with it being a closure, even using the broader definition of a closure.
If you mean that a closure (in Perl) is anything that increases reference count anywhere, then I understand you, but must say that that's the broadest definition of a closure I've ever heard. With that definition though, this below would be equally much a closure:
sub demonstration {
return {
demonstration_data => { demo_data => shift },
};
}
If you mean that it's a closure because you use a lexical variable in there, I disagree that it's a closure. Adding that it must close over/bind a lexical environment (which is what some people think and I think you are referring to), the returned hash reference is not a closure because it doesn't bind anything in its lexical surrounding.
$demonstration_data knows to stick around even though the function ended
In fact, it doesn't. The value it references knows to stay around. The instance of $demonstration_data doesn't stay around itself. Changing $demonstration_data after the latter hash reference is created does not change anything in it. This code below illustrates that.
sub demonstration {
my $demonstration_data = { demo_data => shift };
return {
demonstration_data => $demonstration_data,
}, sub {
$demonstration_data = $_[0];
};
}
my ($data, $modifier) = demonstration('foo');
print Dumper $data;
$modifier->({ a => 1 });
print Dumper $data;
__END__
$VAR1 = {
'demonstration_data' => {
'demo_data' => 'foo'
}
};
$VAR1 = {
'demonstration_data' => {
'demo_data' => 'foo'
}
};
The hash value holds a RV that references the same PVHV as $demonstration_data references. $demonstration_data and demonstration()->{demonstration_data} are different RVs, but reference the same value.
One can argue that the reference operator \ can act as a closure. Looking at lexical variables, it binds the current instance of the lexical variable. The similarity between \ and an anonymous closure and the contrast to other scalar types is demonstrated below.
sub foo {
my $foo = shift;
return
$foo,
[ $foo ],
\$foo,
sub :lvalue { $foo }
;
}
my ($noref, $aref, $sref, $cref) = foo('foo');
my $dump = sub {
print
"\$noref: $noref\n",
"\$aref : $aref->[0]\n",
"\$sref : $$sref\n",
"\$cref : " . $cref->() . "\n\n";
};
$dump->(); $noref = 'bar'; # Changes the first value.
$dump->(); $aref->[0] = 'baz'; # Changes the second value.
$dump->(); $$sref = 'zip'; # Changes the two last values.
$dump->(); $cref->() = 'zap'; # Changes the two last values.
$dump->();
__END__
Long output, run it yourself.
Your hash above is no more closure than the array reference here. Neither the hash or the array bind the variables used in it - they store copies of the values the variables hold. In your case the value is a reference but that is no different from any other non-reference value except that it increases a ref count somewhere when copied, but that has nothing to do with closing over any environment.
One may argue that the array reference itself is a closure and so may be, if you look at [ LIST ] as syntactic sugar for do { my @foo = LIST; \@foo }. That does not make any data structure keeping a reference to the anonymous array a closure though. It's just a data structure that holds a closure.
ihb
Read argumentation in its context!
|