sub skipper_greets {
my $person = shift;
print "Skipper: Hey there, $person!\n";
}
sub gilligan_greets {
my $person = shift;
if ($person eq "Skipper") {
print "Gilligan: Sir, yes, sir, $person!\n";
} else {
print "Gilligan: Hi, $person!\n";
}
}
skipper_greets("Gilligan");
gilligan_greets("Skipper");
This results in:
Skipper: Hey there, Gilligan!
Gilligan: Sir, yes, sir, Skipper!
So far, nothing unusual has happened. Note however that Gilligan has
two different behaviors, depending on whether he's
addressing the Skipper or someone else.
Now, have the Professor walk into the hut. Both of the Minnow crew
greet the newest participant:
skipper_greets("Professor");
gilligan_greets("Professor");
which results in
Skipper: Hey there, Professor!
Gilligan: Hi, Professor!
Now the Professor feels obligated to respond:
sub professor_greets {
my $person = shift;
print "Professor: By my calculations, you must be $person!\n";
}
professor_greets("Gilligan");
professor_greets("Skipper");
resulting in:
Professor: By my calculations, you must be Gilligan!\n";
Professor: By my calculations, you must be Skipper!\n";
Whew. A lot of typing and not very general. If each
person's behavior is in a separate named subroutine
and a new person walks in the door, you have to figure out what other
subroutines to call. You could certainly do it with enough
hard-to-maintain code, but you can simplify the process by adding a
bit of indirection, just as you did with arrays and hashes.
& $ref_to_greeter ( "Gilligan" )
You can also flip it around a bit with the arrow notation:
$ref_to_greeter -> ( "Gilligan" )
That last form is particularly handy when the coderef is contained
within a larger data structure, as you'll see in a
moment.
To have both Gilligan and the Skipper greet the Professor, you merely
need to iterate over all the subroutines:
for my $greet (\&skipper_greets, \&gilligan_greets) {
$greet->("Professor");
}
You've seen the coderefs in a scalar variable and as
an element of a list. Can you put these coderefs into a larger data
structure? Certainly. Create a table that maps people to the behavior
they exhibit to greet others, and then rewrite that previous example
using the table:
sub skipper_greets {
my $person = shift;
print "Skipper: Hey there, $person!\n";
}
sub gilligan_greets {
my $person = shift;
if ($person eq "Skipper") {
print "Gilligan: Sir, yes, sir, $person!\n";
} else {
print "Gilligan: Hi, $person!\n";
}
}
sub professor_greets {
my $person = shift;
print "Professor: By my calculations, you must be $person!\n";
}
my %greets = (
"Gilligan" => \&gilligan_greets,
"Skipper" => \&skipper_greets,
"Professor" => \&professor_greets,
);
for my $person (qw(Skipper Gilligan)) {
$greets{$person}->("Professor");
}
Note that $person is a name, which you look up in
the hash to get to a coderef. Then you dereference that coderef,
passing it the name of the person being greeted, and you get the
correct behavior, resulting in:
Skipper: Hey there, Professor!
Gilligan: Hi, Professor!
Now have everyone greet everyone, in a very friendly room:
sub skipper_greets {
my $person = shift;
print "Skipper: Hey there, $person!\n";
}
sub gilligan_greets {
my $person = shift;
if ($person eq "Skipper") {
print "Gilligan: Sir, yes, sir, $person!\n";
} else {
print "Gilligan: Hi, $person!\n";
}
}
sub professor_greets {
my $person = shift;
print "Professor: By my calculations, you must be $person!\n";
}
my %greets = ... as before ...
my @everyone = sort keys %greets;
for my $greeter (@everyone) {
for my $greeted (@everyone) {
$greets{$greeter}->($greeted)
unless $greeter eq $greeted; # no talking to yourself
}
}
This results in:
Gilligan: Hi, Professor!
Gilligan: Sir, yes, sir, Skipper!
Professor: By my calculations, you must be Gilligan!
Professor: By my calculations, you must be Skipper!
Skipper: Hey there, Gilligan!
Skipper: Hey there, Professor!
Hmm. That's a bit complex. Let's
let them walk into the room one at a time:
sub skipper_greets {
my $person = shift;
print "Skipper: Hey there, $person!\n";
}
sub gilligan_greets {
my $person = shift;
if ($person eq "Skipper") {
print "Gilligan: Sir, yes, sir, $person!\n";
} else {
print "Gilligan: Hi, $person!\n";
}
}
sub professor_greets {
my $person = shift;
print "Professor: By my calculations, you must be $person!\n";
}
my %greets = ... as before ...
my @room; # initially empty
for my $person (qw(Gilligan Skipper Professor)) {
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
}