Приглашаем посетить
Кюхельбекер (kyuhelbeker.lit-info.ru)

Section 7.2.  Anonymous Subroutines

Previous
Table of Contents
Next

7.2. Anonymous Subroutines

In that last example, we never explicitly called subroutines such as professor_greets( ), we only called them indirectly through the coderef. Thus, we wasted some brain cells to come up with a name for the subroutine used only in one other place, to initialize the data structure. But, just as we can create anonymous hashes and arrays, we can create anonymous subroutines !

Let's add another island inhabitant: Ginger. But rather than define her greeting behavior as a named subroutine, we create an anonymous subroutine:

my $ginger = sub {
  my $person = shift;
  print "Ginger: (in a sultry voice) Well hello, $person!\n";
};
$ginger->('Skipper');

An anonymous subroutine looks like an ordinary sub declaration, but there's no name (or prototype) between sub and the block that follows. It's also part of a statement, so we need a trailing semicolon or other expression separator after it in most cases.

sub { ... body of subroutine ... };

The value in $ginger is a coderef, just as if we had defined the following block as a subroutine and then taken a reference to it. When we reach the last statement, we see:

Ginger: (in a sultry voice) Well hello, Skipper!

Although we kept the value in a scalar variable, we could have put that sub { ... } construct directly into the initialization of the greetings hash:

my %greets = (

  Skipper => sub {
    my $person = shift;
    print "Skipper: Hey there, $person!\n";
  },

  Gilligan => sub {
    my $person = shift;
    if ($person eq 'Skipper') {
      print "Gilligan: Sir, yes, sir, $person!\n";
    } else {
      print "Gilligan: Hi, $person!\n";
    }
  },

  Professor => sub {
    my $person = shift;
    print "Professor: By my calculations, you must be $person!\n";
  },

  Ginger => sub {
    my $person = shift;
    print "Ginger: (in a sultry voice) Well hello, $person!\n";
  },

);

my @room; # initially empty
for my $person (qw(Gilligan Skipper Professor Ginger)) {
  print "\n";
  print "$person walks into the room.\n";
  for my $room_person (@room) {
    $greets{$person}->($room_person); # speaks
    $greets{$room_person}->($person); # gets reply
  }
  push @room, $person; # come in, get comfy
}

Notice how much it simplifies the code. The subroutine definitions are right within the only data structure that references them directly. The result is straightforward:

Gilligan walks into the room.

Skipper walks into the room.
Skipper: Hey there, Gilligan!
Gilligan: Sir, yes, sir, Skipper!

Professor walks into the room.
Professor: By my calculations, you must be Gilligan!
Gilligan: Hi, Professor!
Professor: By my calculations, you must be Skipper!
Skipper: Hey there, Professor!

Ginger walks into the room.
Ginger: (in a sultry voice) Well hello, Gilligan!
Gilligan: Hi, Ginger!
Ginger: (in a sultry voice) Well hello, Skipper!
Skipper: Hey there, Ginger!
Ginger: (in a sultry voice) Well hello, Professor!
Professor: By my calculations, you must be Ginger!

Adding a few more castaways is as simple as putting the entry for the greeting behavior into the hash and adding them into the list of people entering the room. We get this scaling of effort because we've preserved the behavior as data over which you can iterate and look up, thanks to your friendly subroutine references.


Previous
Table of Contents
Next