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

i searched the site, but kept getting 'the magic of passing arguments to subroutines' and such things (i.e., exactly what i don't want!)

i have a function that takes an anonymous array of subroutines to do some 'stuff' with them, but i need to know how to pass the subs. I tried this:

sub my_sub { do_stuff } sub take_subs { do_more_stuff } take_subs([&my_sub]);
This, however, just evaluates my_sub and gives take_subs the return value. What will work?

Replies are listed 'Best First'.
Re: subs as args
by Juerd (Abbot) on Jul 06, 2002 at 14:31 UTC

    This, however, just evaluates my_sub and gives take_subs the return value. What will work?

    You could use a reference (perlref) to the sub:

    use Carp; sub sum { croak 'Usage: sum($first, $second)' unless @_ == 2; my ($first, $second) = @_; return $first + $second; } sub call { my ($sub, @args) = @_; croak 'Usage: call(\&sub, @args)' unless ref $sub and ref $sub eq +'CODE'; return $sub->(@args); } $\ = "\n"; print call(\&sum, 1, 3); # Error happens in call() [line 12], because that's where sum() is cal +led! print call(\&sum, 5);

    - Yes, I reinvent wheels.
    - Spam: Visit eurotraQ.
    

Re: subs as args
by broquaint (Abbot) on Jul 06, 2002 at 14:34 UTC
    You need to pass it by reference like so
    sub take_subs { $_->() for @_; } sub foo { print "in foo()\n" } sub bar { print "in bar()\n" } take_subs(\&foo, \&bar); # ^^ ^^ __output__ in foo() in bar()
    See the perlsub and perlref manpages for more details.
    HTH

    _________
    broquaint

Re: subs as args
by Anonymous Monk on Jul 06, 2002 at 14:29 UTC
    When you hear "anonymous", think "reference".

    When you think reference, think \. There is also often an anonymous constructor available.

    sub demo { print "This is the demo function I will pass\n"; } sub take_subs { foreach (@_) { $_->(); } } take_subs(\&demo, sub {print "Another way!\n"});
Re: subs as args
by flounder99 (Friar) on Jul 07, 2002 at 02:29 UTC
    What you are doing are references to a sub. Here are some examples of refs and anonymous subs.
    use strict; #this is variable holding a ref to an anon sub my $mysub1 = sub { print "mysub1 called\n" }; #this is a regular subroutine sub mysub2 { print "mysub2 called\n"; } #call this with a refrerence to an array sub references sub take_subs { my @arrayofsubs= @{$_[0]}; print "take_subs called, now calling each subref\n"; foreach (@arrayofsubs) { &$_; } } # call take_subs with each type take_subs ([ $mysub1, # variable holding anon sub reference \&mysub2, # sub reference sub { print "anonymous sub called\n" } #anon sub ]); __OUTPUT__ take_subs called, now calling each subref mysub1 called mysub2 called anonymous sub called

    --

    flounder

Take the next step into closures (Re: subs as args)
by dragonchild (Archbishop) on Jul 08, 2002 at 16:38 UTC
    Your question has been well-answered. However, I'd like to take this to the next level and introduce you (if you already don't know) to closures.

    A closure is an anonymous subroutine that's been created by another subroutine. The canonical example of a closure is a counter generator.

    sub create_counter { my $counter = 0; return sub { $counter++ }; } # # # my $counter = create_counter(); while (&$counter < $Some_Value) { &DO_Stuff; }
    This seems like overkill, but it allows for two things:
    1. More than one counter at the same time
    2. Customizable counters
    If we just do the following ...
    sub create_upper_bounded_counter { my ($upper_bound) = @_; my $counter = 0; return sub { $counter++ <= $upper_bound ? 1 : 0 }; } # # # my $bounded_counter = create_upper_bounded_counter(10); while (&$bounded_counter) { &Do_Stuff; }
    Hence why closures are sometimes called "function templates". I've used closures as a way to help organize a set of functions that transformed an input in one of three basic ways. It was just that the transformation changed based on a set of definable parameters. (Take the 3rd thing in this instance, the 4th in that instance, but do the exact same thing.) Closures are also used to parse stuff. I believe it was tye (or tilly) that wrote a closure-based HTML parser as an example of functional programming some months back. Really interesting stuff.

    ------
    We are the carpenters and bricklayers of the Information Age.

    Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.

      A closure is an anonymous subroutine that's been created by another subroutine.
      Not quite. That's a bad meme that perists, despite our efforts to the contrary.

      A closure is subroutine that has captured its lexical environment which has now gone out of scope.

      This is orthogonal to the concept of an anonymous subroutine, which may or may not need to be "closed". In other words, the properties of "having a name" and "being a closure" are uncorrelated.

      Here's a named subroutine that's a closure:

      BEGIN { my $current = 0; sub gimme_next { ++$current } }
      This named subroutine gimme_next is a closure. And here's an example of an anonymous subroutine which is not a closure:
      my $foo = sub { 2 * shift };
      So, please don't confuse anonymous subroutine with closure: they're really different things.

      -- Randal L. Schwartz, Perl hacker

        I realize this is an old post, but I just came from 423779...
        A closure is subroutine that has captured its lexical environment which has now gone out of scope.
        For completeness, I would add that not all closures are subroutines; regular expressions that use the (?{}) construct can also be closures. For example,
        sub a { my $i = 0; # note that the regex is compiled only once () = shift =~ /a(?{print $i++})/g; } a("ababa"); # prints 0 1 2 a("ajaja"); # prints 3 4 5

        I don't know if these regular expressions are implemented internally as subroutines, but they certainly don't look like subroutines, so people are often surprised to see this behavior.

        Of course, you are absolutely correct.

        However, I maintain that closures are an extremely difficult thing for non-functional programmers to grasp. Using an anonymous subroutine returned from a closure-generator gives someone the idea of what's going on so that they can at least grasp the basic feel.

        I say this cause that's how I learned about them. This isn't to say that in an environment where someone could be guaranteed to have the learner's attention for more than one reading, the more correct notion should be pushed.

        I guess what I'm saying is that anon subs are a tool. Closures are a concept. I often implement the concept "closure" using the tool "anon sub". (Just like I sometimes prefer implmenting the concept "object instance" using the tool "blessed closure".)

        ------
        We are the carpenters and bricklayers of the Information Age.

        Don't go borrowing trouble. For programmers, this means Worry only about what you need to implement.