Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Exploring the uses of anonymous subs

Tags:

perl

I've always been somewhat confused about the purpose and usage of anonymous subs in perl. I understand the concept, but looking for examples and explanations on the value of this practice.

To be clear:

sub foo { ... }   # <--- named sub
sub { ... }       # <--- anonymous sub

For example:

$ perl -e 'print sub { 1 }'
CODE(0xa4ab6c)

Tells me that sub returns a scalar value. So, I can do:

$ perl -e '$a = sub { 1 }; print $a'

For the same output as above. This of course holds true for all scalar values, so you can load arrays or hashes with anonymous subs.

The question is, how do I use these subs? Why would I want to use them?

And for a gold star, is there any problem which can only be resolved with an anonymous sub?

like image 884
TLP Avatar asked Jun 30 '11 13:06

TLP


8 Answers

Anonymous subroutines can be used for all sorts of things.

  1. Callbacks for event handling systems:

    my $obj = Some::Obj->new;
    
    $obj->on_event(sub {...});
    
  2. Iterators:

    sub stream {my $args = \@_; sub {shift @$args}}
    
    my $s = stream 1, 2, 3;
    
    say $s->(); # 1
    say $s->(); # 2 
    
  3. Higher Order Functions:

    sub apply (&@) {
        my $code = shift;
        $code->() for my @ret = @_;
        @ret
    }
    
    my @clean = apply {s/\W+/_/g} 'some string', 'another string.';
    
    say $clean[0]; #  'some_string'
    
  4. Creating aliased arrays:

    my $alias = sub {\@_}->(my $x, my $y);
    
    $alias[0]++;
    $alias[1] = 5;
    
    say "$x $y";  # '1 5''
    
  5. Dynamic programming with closures (such as creating a bunch of subroutines that only differ by a small amount):

    for my $name (qw(list of names)) {
        no strict 'refs';
        *$name = sub {... something_with($name) ...};
    }
    

There is no situation where an anonymous subroutine can do anything that a named subroutine can not. The my $ref = sub {...} constructor is equivalent to the following:

sub throw_away_name {...}

my $ref = \&throw_away_name;

without having to bother with deciding on a unique 'throw_away_name' for each sub.

The equivalence also goes the other way, with sub name {...} being equivalent to:

 BEGIN {*name = sub {...}}

So other than the name, the code reference created by either method is the same.

To call a subroutine reference, you can use any of the following:

 $code->();         # calls with no args
 $code->(1, 2, 3);  # calls with args (1, 2, 3)
 &$code();          # calls with no args
 &$code;            # calls with whatever @_ currently is

You can even use code references as methods on blessed or unblessed scalars:

 my $list = sub {@{ $_[0] }};

 say for [1 .. 10]->$list  # which prints 1 .. 10 
like image 121
Eric Strom Avatar answered Nov 07 '22 19:11

Eric Strom


You can use it to create iterators.

use strict;
use warnings;

use 5.012;

sub fib_it {
  my ($m, $n) = (0, 0);

  return sub {
    my $val = ( $m + $n );
    $val = 1 unless $val;
    ($m, $n) = ($n, $val);
    return $val;
  }
}

my $fibber = fib_it;
say $fibber->() for (1..3); ### 1 1 2

my $fibber2 = fib_it;
say $fibber2->() for (1..5); ### 1 1 2 3 5
say $fibber->() for (1..3); #### 3 5 8
like image 35
Oesor Avatar answered Nov 07 '22 18:11

Oesor


Anonymous subroutines can be used to create closures.

Closure is a notion out of the Lisp world that says if you define an anonymous function in a particular lexical context, it pretends to run in that context even when it's called outside the context.

  • perlref
  • What's a closure?
like image 27
Eugene Yarmash Avatar answered Nov 07 '22 18:11

Eugene Yarmash


Here's something similar you might have seen before:

@new_list = map { $_ + 1 } @old_list;

And also:

@sorted = sort { $a <=> $b } @unsorted;

Neither of those are anonymous subs, but their behavior can be imitated in your functions with anonymous subs. They don't need the sub keyword because the functions are (essentially) prototyped to have their first argument be a subroutine, and Perl recognizes that as a special case where sub can be left off. (The functions also set the requisite variables to meaningful values before calling the subroutines you provided in order to simplify argument passing, but that's not related.)

You can write your own map-like function:

sub mapgrep (&@) { # make changes and also filter based on defined-ness
  my ($func, @list) = @_;
  my @new;
  for my $i (@list) {
    my $j = $func->($i);
    push @new, $j if defined $j;
  }
}

The magic to make it work with $_ is a bit much to write here - the above version only works for subs that take arguments.

like image 36
Chris Lutz Avatar answered Nov 07 '22 17:11

Chris Lutz


Well I wrote a SAX parser for perl that is event driven. You can pass anonymous subs to the begin/end events on an element.

my $str = "<xml><row><data></data></row></xml>":

my $parser = SAXParser->new();

$parser->when('row')->begin(sub {
    my ($element) = @_;
    push(@rows, $row);
});

$parser->when('row')->end(sub {
   ## do something like serialize it or whatever
});

$parser->parse($str);
like image 24
Nathan Romano Avatar answered Nov 07 '22 17:11

Nathan Romano


They are generally used when you want to pass a sub to another bit of code. Often this is a case of "When X happens (in third party code) do Y".

For example. When defining an attribute in Moose, you can specify the default value of that attribute using a sub. Given a class which has, as part of its definition:

  has 'size' => (
      is => 'ro',
      default =>
          sub { ( 'small', 'medium', 'large' )[ int( rand 3 ) ] },
      predicate => 'has_size',
  );

Whenever an instance of that class is created without an explicit size being passed, the sub will be called and the return value will be the size for that object.

If we switch to another language to give a different example, you'll find a similar concept in JavaScript.

var b = document.getElementById('my_button').
b.addEventListener('click', function (e) { alert('clicked!'); });
like image 40
Quentin Avatar answered Nov 07 '22 17:11

Quentin


In your example, you haven't actually called created subroutine. Call is performed with either &$a or $a->() syntax. What you've done is that you stored a reference to subroutine in $a, then stringifyed it and printed result. Compare:

my $a = sub {1};
my $b = sub {1};
print join("\n", $a, $a->(), $b, $b->());
like image 33
Dur-Randir Avatar answered Nov 07 '22 18:11

Dur-Randir


These are subs for the lazy programmer. You can use them for local throw-away functions and can save some typing. Instead of

sub x { ... }
my $function_ptr = \&x;

you can now use

my $function_ptr = sub { ... };

The anonymous functions are also private, and can only be accessed through the $function_ptr, so they don't have an entry in the symbol table.

like image 20
hexcoder Avatar answered Nov 07 '22 17:11

hexcoder