zorglups has asked for the wisdom of the Perl Monks concerning the following question:

Hi,

A little question on anonymous subroutines ?

How to declare the sub so that the $parameter gets evaluated at the declaration ?

In a few words, with the following code, I would like to have $print_ref->() always print "param at declaration".

Thanks,

Pierre

#!/usr/bin/perl use strict; my $parameter = "param at declaration\n"; my $print_ref = sub { print $parameter }; $print_ref->(); # prints: param at declaration $parameter = "param after declaration\n"; $print_ref->(); # prints: param after declaration exit;
  • Comment on How to get variable evaluation in anonymous subroutines declaration
  • Download Code

Replies are listed 'Best First'.
Re: How to get variable evaluation in anonymous subroutines declaration
by Corion (Patriarch) on Jan 21, 2009 at 15:14 UTC

    Make a copy of $parameter before binding to it:

    sub make_print_ref { my ($parameter) = @_; return sub { print $parameter }; }; my $print_ref = make_print_ref(...);

    I'm not sure if any of the Curry modules provide such a facility, but it isn't too hard to roll one yourself.

      You made my day !!! Thanks a lot.
Re: How to get variable evaluation in anonymous subroutines declaration
by AnomalousMonk (Archbishop) on Jan 21, 2009 at 17:34 UTC
    A  do BLOCK also forms a closure without the need for either a named or anonymous secondary subroutine.
    >perl -wMstrict -le "my $param = 'param is foo'; my $coderef = do { my $sub_param = $param; sub { print $sub_param } }; $coderef->(); $param = 'param now bar'; $coderef->(); " param is foo param is foo
Re: How to get variable evaluation in anonymous subroutines declaration
by kyle (Abbot) on Jan 21, 2009 at 15:32 UTC

    Corion is correct. If, for some reason, you don't want to define a sub that does this, you can use an anonymous sub the same way.

    my $parameter = qq{param at declaration\n}; my $print_ref = sub { my ($p) = @_; sub { print $p } }->( $parameter ) +; $print_ref->(); $parameter = qq{param after declaration\n}; $print_ref->(); __END__ param at declaration param at declaration

    I wouldn't recommend this for anything more complicated than a single line, however. I wouldn't want to read to the end of a block of code to find "->(...)" dangling off of it.

      This worked as well. I will stick to Corion's suggestion because i would like to be able to understand my code when I will have to read it next time ;-)

      Thanks a lot for the comment.

Re: How to get variable evaluation in anonymous subroutines declaration
by mpeever (Friar) on Jan 21, 2009 at 20:27 UTC

    It's important to remember that closures close over variables, not values. So if the variable changes in the enclosing scope, those changes are reflected in the closure.

    Copying the variable before using it essentially works around the concept of closure by creating a new variable in the function, which is in a "closer" scope. I personally think this is the best method to work around this behaviour, if that's what you want to do.

Re: How to get variable evaluation in anonymous subroutines declaration
by ig (Vicar) on Jan 21, 2009 at 21:06 UTC
    The solutions that have been provided all use "closure" which can be difficult to understand and is sometimes surprising. Reading perlref and Closure on Closures might help you to understand what closure is, how it works and other uses for it.