in reply to Re^2: Ways to implement a closure
in thread Ways to implement a closure
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:
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.sub demonstration { return { demonstration_data => { demo_data => shift }, }; }
$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.
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.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' } };
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.
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.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.
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!
|
---|