Reputation: 1848
I am trying to use the GetOptions
function from GetOpt::Long
to call a subroutine that accepts an argument. However, the subroutine gets called regardless of whether the option is specified on the command line. This unexpected behavior does not occur if an argument is not passed to the subroutine in the GetOptions
line.
What follows is a minimal demonstration of the problem:
If an argument is provided to the subroutine in the GetOptions
line, the subroutine ends up being called regardless of whether its controlling option is supplied on the command line:
$ cat a1.pl
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long qw(GetOptions);
my $var="entered";
GetOptions ( "opt" => \&sub1($var) );
sub sub1 { print "sub1 $_[0]\n"; }
$ perl a1.pl --opt
sub1 entered
$ perl a1.pl
sub1 entered
In contrast, if the subroutine is called in GetOptions
without an argument, it behaves appropriately:
$ cat a2.pl
#!/usr/bin/perl
use strict;
use warnings;
use Getopt::Long qw(GetOptions);
GetOptions ( "opt" => \&sub2 );
sub sub2 { print "sub2 entered\n"; }
$ perl a2.pl --opt
sub2 entered
$ perl a2.pl
What am I doing wrong?
PS: I know that I can simply set a variable that controls whether the subroutine is called after the GetOptions
block, but I would like to determine the correct syntax for calling the subroutine within the GetOptions
line, as well as understand why the observed behavior is happening.
Upvotes: 4
Views: 1549
Reputation: 66881
The module expects a code reference, and that is taken with the sub name alone (\&name
) or as an anonymous sub; there is no notion of "arguments" as you are not making a function call but rather obtaining a reference (to code). Then call you sub in that code. Details follow.
Associate the option with an anonymous subroutine, inside of which you can call your sub
use warnings;
use strict;
use feature 'say';
use Getopt::Long;
my $opt;
my $var = 'entered';
GetOptions ( 'opt' => sub { $opt = 1; sub1($var) } );
sub sub1 { say "sub1 $_[0]"; }
Or use 'opt' => \&cb
and in the sub cb()
call sub1(...)
. This callback is passed the option name and value (or name, key, and value in case of a hash), and doesn't take other arguments. So you cannot in any way dynamically resolve what arguments to pass to sub1()
.
The invocation in the question is not how a subroutine reference is obtained; you must only use the subroutine name, \&name
. This is not about Getopt
, which just wants a code reference.
When you attempt to "pass arguments" that isn't a coderef anymore but the sub is executed and then the reference taken of its return; same as \sub()
or \( sub() )
. This can be seen by
perl -wE'sub tt { say "@_"; return "ret" }; $r = \&tt("hi"); say $$r'
what prints
hi ret
While this just isn't a way to take a reference let me still warn of possible surprises (if one ends up trying to take a "reference to a list")
Upvotes: 1
Reputation: 86774
It's been a few years since I did much Perl, but I'm pretty sure it is because
\&sub1($var)
is a reference to the result of invoking sub1
. That is, the line
GetOptions ( "opt" => \&sub1($var) );
actually invokes sub($var)
as part of constructing the argument list to GetOptions
. This looks like a corner case in the syntax, you are taking a reference to the result of that invocation.
This should clear things up:
$ perl -de0
Loading DB routines from perl5db.pl version 1.49_001
Editor support available.
Enter h or 'h h' for help, or 'man perldebug' for more help.
main::(-e:1): 0
DB<1> sub sub1 { print "sub1\n"; }
DB<2> sub1()
sub1
DB<3> &sub1
sub1
DB<4> \&sub1
DB<5> x \&sub1
0 CODE(0x804d7fe8)
-> &main::sub1 in (eval 6)[/usr/lib/perl5/5.22/perl5db.pl:737]:2-2
DB<6> x \&sub1()
sub1
0 SCALAR(0x804ee7f0)
-> 1
Upvotes: 1