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:

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!