I want to define a Perl function (call it "difference") which depends on a command-line argument. The following code doesn't work:
if ("square" eq $ARGV[0]) {sub difference {return ($_[0] - $_[1]) ** 2}}
elsif ("constant" eq $ARGV[0]) {sub difference {return 1}}
It appears that the condition is ignored, and therefore the "difference" function gets the second definition regardless of the value of $ARGV[0].
I can make the code work by putting a condition into the function:
sub difference {
if ("square" eq $ARGV[0]) {return ($_[0] - $_[1]) ** 2}
elsif ("constant" eq $ARGV[0]) {return 1}
}
But this is not really my intention -- I don't need the condition to be evaluated each time during execution. I just need a way to influence the definition of the function.
My questions are:
Others have already presented the syntax you requested, but I would recommend using more explicit subroutine references for this, so that you can freely manipulate the reference without manipulating the definition. For example:
sub square_difference { return ($_[0] - $_[1]) ** 2 }
sub constant_difference { return 1 }
my %lookup = (
'square' => \&square_difference,
'constant' => \&constant_difference,
);
my $difference = $lookup{$ARGV[0]} || die "USAGE: $0 square|constant\n";
print &$difference(4, 1), "\n";
It's the same basic approach, but I think this syntax will let you map arguments to subroutines a bit more conveniently as you add more of each. Note this is a variation on the Strategy Pattern, if you're into that kind of thing.
What you want to do can be achieved like this:
if ($ARGV[0] eq 'square') {
*difference = sub { return ($_[0] - $_[1]) ** 2 };
}
elsif ($ARGV[0] eq 'constant') {
*difference = sub { return 1 };
}
I haven't personally done a lot of this, but you might want to use a variable to hold the subroutine:
my $difference;
if ("square" eq $ARGV[0]) {$difference = sub {return ($_[0] - $_[1]) ** 2}}
elsif ("constant" eq $ARGV[0]) {$difference = sub {return 1}}
Call with:
&{ $difference }(args);
Or:
&$difference(args);
Or, as suggested by Leon Timmermans:
$difference->(args);
A bit of explanation - this declares a variable called $difference
and, depending on your conditions, sets it to hold a reference to an anonymous subroutine. So you have to dereference $difference
as a subroutine (hence the &
in front) in order for it to call the subroutine.
EDIT: Code tested and works.
One more EDIT:
Jesus, I'm so used to use
ing strict
and warnings
that I forget they're optional.
But seriously. Always use strict;
and use warnings;
. That will help catch things like this, and give you nice helpful error messages that explain what's wrong. I've never had to use a debugger in my life because of strict
and warnings
- that's how good the error-checking messages are. They'll catch all kinds of things like this, and even give you helpful messages as to why they're wrong.
So please, whenever you write something, no matter how small (unless it's obfuscated), always use strict;
and use warnings;
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With