in reply to Ways to implement a closure

A closure is a type of subroutine, so if you rule out anonymous subroutines, that only leaves named subroutines. dragonchild already posted an example of that.

However, two things come to mind which are similiar to closures: tied variables and objects. Both can be used to execute code on hidden or encapsulated data. Refer to perlobj and perltie.

Replies are listed 'Best First'.
Re^2: Ways to implement a closure
by tilly (Archbishop) on Oct 15, 2004 at 19:39 UTC
    Some people define any data structure that closes over an environment to be a closure. (Some people don't.) In which case this is a closure:
    sub demonstration { my $demonstration_data = { demo_data => shift }; return { demonstration_data => $demonstration_data, }; }
    because $demonstration_data knows to stick around even though the function ended.

    An example of a language where the data would not be expected to stick around is C - if you don't watch out the demonstration data would be stuck on the stack, and a few function calls later would not be there to be found.

      I see. Well there you go, yet another way!

      Nit: that code works in C (given some imagined Hash class), and the data does stick around:

      Hash<...>* demonstration<...>(... a) Hash<...>* hash_ptr = new Hash<...>("demo_data", a); return new Hash<...>( "demonstration_data", hash_ptr ); }

      I think you meant this:

      sub demonstration { my %demonstration_data = ( demo_data => shift ); return { demonstration_data => \%demonstration_data, }; }

      Which wouldn't work in C:

      Hash<...>* demonstration<...>(... a) Hash<...> hash("demo_data", a); return new Hash<...>( "demonstration_data", \hash XXX BUG ); }
        C does not have templates OR classes! (Not that this is a bad thing...)

      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!