Beefy Boxes and Bandwidth Generously Provided by pair Networks
Don't ask to ask, just ask
 
PerlMonks  

Re^2: closures: anonymous subs vs function templates?

by Laurent_R (Canon)
on Dec 21, 2014 at 18:46 UTC ( [id://1110980]=note: print w/replies, xml ) Need Help??


in reply to Re: closures: anonymous subs vs function templates?
in thread closures: anonymous subs vs function templates?

Hi Athanasius
But if we attempt to do this with a function template, the warning we get:
Use of uninitialized value in addition (+) at...
shows that the inner sub is actually run at the time when the outer sub is called.

I may have misunderstood this part of your post, but I interpreted it to mean that it is not possible to build a closure with a function template. That surprised me quite a bit, so I decided to try, modifying your sample code.

When I run this code:

use strict; use warnings; local *f1 = make_adder( 20); printf "result f1 = %d\n", f1(10); local *f2 = make_adder(555); printf "result f2 = %d\n", f2(10); sub make_adder { my $addpiece = shift; print "\$addpiece = $addpiece\n"; *inner = sub { return shift() + $addpiece; }; return *inner; }
I get a warning, but it seems to work nonetheless (at least to print the correct values):
$ perl func_template2.pl $addpiece = 20 result f1 = 30 $addpiece = 555 Subroutine main::inner redefined at func_template2.pl line 15. result f2 = 565
Fair enough, the warning says that the inner function is being redefined, which is of course not a very good idea in this context (and, as we know and as you have shown with your example, we would not have that with lexical code refs, which is a good reason to think that lexical code refs are superior to function templates for that kind of things). But, yet, the functions f1 and f2 can still print the right values, meaning that they apparently can close on these values. And I don't get any warning if I use only f1 (and not f2).

I would tend to think that it is likely to be my fault and that I probably did not understand correctly what you meant to say, but, if such is the case, I would like to ask you to explain further what you meant.

Replies are listed 'Best First'.
Re^3: closures: anonymous subs vs function templates?
by Athanasius (Archbishop) on Dec 22, 2014 at 03:17 UTC

    Hello Laurent_R,

    You understood me correctly, and it appears I was wrong: you have shown that it is possible to build a closure using function templates. But I note that, to get the syntax to work, you had to remove the local from the definition of *inner within sub make_adder, and that makes *inner a package global sub. In fact, what sub make_adder returns is simply the string *main::inner. So we can dispense with make_adder’s return value and the assignments to *f1 and *f2 altogether:

    #! perl use strict; use warnings; use v5.14; make_adder(20); say inner(10); make_adder(25); say inner(10); sub make_adder { my $addpiece = shift; print "\$addpiece = $addpiece\n"; *inner = sub { return shift() + $addpiece; }; }

    Output:

    13:02 >perl 1102_SoPW.pl $addpiece = 20 30 $addpiece = 25 Subroutine main::inner redefined at 1102_SoPW.pl line 15. 35 13:02 >

    This approach is inferior to the standard technique (references to anonymous subroutines) in at least two ways:

    1. Each call to make_adder creates a new closure, and the previous closure is no longer available (hence the warning message).
    2. The memory allocated to $addpiece will never be garbage collected as long as the script is running.

    Hope that helps,

    Athanasius <°(((><contra mundum Iustus alius egestas vitae, eros Piratica,

      In my function template example, I put the local in front of *inner for just that reason - to limit the scope of inner to the block in which it is defined for the purposes of both limiting access and improving garbage collection.

      I appreciated the conversation all of these examples has created. I've learned a few things in the process. I thank all of you who have contributed this analysis.

      I of course did not want to promote function templates for such use cases, but just tried to see how they could work out. I definitely agree that the approach with references to anoonymous subroutines is vastly superior, especially in view of your first remark: a new closure is destroying the previous one.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://1110980]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others drinking their drinks and smoking their pipes about the Monastery: (8)
As of 2024-04-18 15:00 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found