Perl Getopt::Long options are not boolean testable

I often get into arguments with coworkers and peers about avoiding libraries for what are simple things to code myself.

I didn't think I would still have this discussion after the infamous leftpad library broke pretty much everything, which is not only a good example of the dangers of relying on other libraries, but also how ridiculous people can be with using libraries when they are totally unnecessary.

But the argument still happens. And most recently, I got flak from one of my coworkers for not using Getopt.

I've never been a fan of Getopt. I find that it allows you to reduce n lines of code, after reading all of the Getopt documentation and special cases, to n lines of less readable code.

Not terribly useful in my book.

It turns out that arg parsing is really easy, and if I need any of the higher features that Getopt offers, I'll code them myself, or something more complex, like the very powerful argument parsing I developed for album, which I suppose I should probably turn into a library someday. :)

Anyways, I used Getopt at work, and sure enough, it caused a bug.

Getopt allows you to use subroutine handlers for more complex options and it passes in the option name and value. Except not quite. It actually passes in an object that can stringify to the name and value. Except not quite. From the docs section on "User-defined subroutines to handle options"

The first argument is the name of the option. (Actually, it is an object that stringifies to the name of the option.)

The problem is that this object, for whatever reason, does not evaluate as true if a conditional (perhaps they've foolishly overwritten the '=' operator?). Which means that if you save that in some other variable and later test if that variable has been set, you'll get the wrong answer. You need to force the stringification by saving it in quotes. Here's a simple example of how this might bite you:

use Getopt::Long;

my $someOption;

GetOptions(
    "myboolopt"        => \&setOption,
) or die "Error parsing command-line arguments\n";

sub setOption {
  my ($optionName) = @_;
  print "Option Handler:  $optionName\n";
  $someOption = $optionName;
	# Not what you'd expect!  $someOption is now Getopt::Long::CallBack
	# Fix with:  $someOption = "$optionName"
}

print "someOption has value: $someOption\n";
print "someOption is set\n" if $someOption;
print "someOption is **NOT** set\n" if !$someOption;

Output is quite logically terrifying:

Option Handler:  myboolopt
someOption has value: myboolopt
someOption is **NOT** set


Back to DaveSource Bugs