Beefy Boxes and Bandwidth Generously Provided by pair Networks
Do you know where your variables are?
 
PerlMonks  

Getopt::Long good style?

by Skeeve (Parson)
on Jul 28, 2004 at 09:14 UTC ( [id://377971]=perlquestion: print w/replies, xml ) Need Help??

Skeeve has asked for the wisdom of the Perl Monks concerning the following question:

I don't use Getopt::Long very often so I tend to forget how to use it. Today I need it again and so I decided to create a "template" for me to use should I need it again.

I came up with the code below and ask myself whether or not it's wise to use an anonymous subroutine for the help function, the way I did. It's just defined in the call of GetOptions. Will it give any improvement, e.g. memory wise?
#!/usr/bin/perl use strict; use warnings; use Getopt::Long; my ( # options $verbose, $debug, $file, @columns, ); $file= 'default.txt'; die "Use --help for options\n" unless GetOptions( 'v' => \$verbose, 'verbose!' => \$verbose, 'debug+' => \$debug, 'file=s' => \$file, 'c|column=i' => \@columns, 'h|help' => sub { print <<HELP; Help text here... HELP exit; }, ); print "OKAY\n"; # Program goes here...

Replies are listed 'Best First'.
Re: Getopt::Long good style?
by cosimo (Hermit) on Jul 28, 2004 at 11:19 UTC
    You might want to take a look at Getopt-Auto, which goes further in the direction you are heading with your good template.
      Thanks for the hint. Looks interesting.
Re: Getopt::Long good style?
by gaal (Parson) on Jul 28, 2004 at 10:25 UTC
    You shouldn't be worried about the memory impact of a single sub. In this case the difference is completely meaningless.

    Your code is fine. Anonymous subroutines might take more memory than named ones if they close on lexical variables, so if you create many (*many*) instances of them you might start feeling the difference, but in this case, you won't.

Re: Getopt::Long good style?
by naChoZ (Curate) on Jul 28, 2004 at 12:54 UTC

    One thing you can do to earn a few style points but mainly to maximize your use of Getopt::Long is to use a hash. For one thing, it allows you to pass a simple hashref so that you don't end up doing any ugly $main::opt_foo business when you're trying to access your options from another class. And it also makes it easy to have default options.

    my %opts = ( 'foo' => 'default_value', 'bar' => 'another_default_value', 'baz' => 'yet_another' ); GetOptions( \%opts, override, default, values, here); My::Class->method( \%opts ); # ... elsewhere in your code ... package My::Class; my $class = shift; my $opts_ref = shift; ...

    Also, if you're going to use an anonymous sub for help, it reads a little better if you do:

    'h|help' => sub { help() },
    then have sub help print out your help text.

    --
    "A long habit of not thinking a thing wrong, gives it a superficial appearance of being right." -- Thomas Paine
    naChoZ

      Also worth a mention simply because I think it's nifty, Getopt::Long has an auto_help option. If you throw some POD in your code (specifically a SYNOPSIS section), turning auto_help on will automatically display that section.

      use Getopt::Long qw/:config auto_help/; ... =pod =head1 SYNOPSIS some help text... =cut ...

      --
      "A long habit of not thinking a thing wrong, gives it a superficial appearance of being right." -- Thomas Paine
      naChoZ

      I didn't understand the "hashy" part of GetOpt::Long yet, but it sounds good to me.

      Regarding the
      'h|help' => sub { help() },
      part, I don't get the point. What's the advantage over:
      'h|help' => \&help,

        That way is fine also. I tend to shy away from &'s in general out of personal preference.

        I just like...

        'h|help' => sub { help() }, ... sub help { ... }

        better than...

        'h|help' => \&help, ... my $help = sub { ... }

        --
        "A long habit of not thinking a thing wrong, gives it a superficial appearance of being right." -- Thomas Paine
        naChoZ

Re: Getopt::Long good style? (tight scoping)
by grinder (Bishop) on Jul 28, 2004 at 13:17 UTC

    I have no problems with the anonymous sub. I do take issue, though, with the list of scalars for options. I much prefer to use a hash to keep things in one place.

    But hang on! If you mispell a scalar, the compiler will bark at you. If you mispell a hash key, the runtime will autovivify it for you. Hmm.

    But that's ok too, because what I really prefer doing is hiding it all away in a scope, and declaring subs as The Only Way of retrieving values. Admittedly, you still don't get a compile time error, but it will blow up at runtime if you get things worng. My template looks something like:

    { use Getopt::Long; my %opt; GetOptions ( \%opt, qw/ verbose! file:s debug+ help/ ) || die sub { print <<END_OF_HELP; $0: you blew it! Switches are as follows: --help | -h this help screen ... END_OF_HELP } sub debug { exists $opt{debug} ? $opt{debug} : 0 } sub verbose { exists $opt{verbose} ? 1 : 0 } sub file { if( not exists $opt{f} ) { '' } elsif( not defined $opt{f} ) { '/etc/passwd' } else { $opt{f} } } }

    The sub file lets you distinguish between an argument that is absent (return an empty string), present, but with no value (return a fixed name) or present with a value (return the value).

    Since the %opt hash isn't available outside the scope, the program can't (accidentally or on purpose) modify the contents. This may be construed as a feature.

    - another intruder with the mooring of the heat of the Perl

Re: Getopt::Long good style?
by wufnik (Friar) on Jul 28, 2004 at 12:50 UTC
    hola monseiur Skeeve.

    normally i would be absolutely the last person to wade in with any points re: style, mostly because my points re: code feng shui are invariably ignored, but being a heavy Getopt::Long user, i have one simple point i feel may be relevant.

    i frequently find i use functions, within the key GetOptions call of Getopt::Long, to actually parse command line arguments. one such script needs to get a list of variables which i want to calculate conditional probabilities for: here is he call to GetOptions.

    GetOptions(\%runconfig, "load=s" => \&loadAttributeDescriptions, "loadconfig=s" => \&loadconfig, "dumpconfig=s" => \$dumpconfig, "tables=s" => \$tables, "prec:i" => \$precision, "decorate" => \$decorate, "i=s@", # include a nominal field. "arff", # arff file [data mining] "max:i", # examine file to this length "quiet", # do not spit out csv "filter=s" => \&addfilter, "cp=s" => \&addcp, # array of [ant [ dependents ] ] "cptformat=s", # cp table format "prune", # get rid of 0 info columns "help" => \$help, "man" => \$man ) or pod2usage(-verbose=>1) && exit(1);
    as you can see, it's long, and there are a number of functions that have to be called to deal with the vagaries of what i need & want.

    at least some of these vagaries are useful. witness the function addcp: this allows me to tell the script which conditional probabilities i need evaluated, ie:
    cptplus.pl --cp="charm|perlmonk,cyberpunk,neovictorian"
    useful, but it requires the overhead of a function, which goes something like...
    sub addcp{ my $cpstring = $_[1]; $cpstring =~ s/^([A-Za-z\-\_0-9]+)\|//; my $antecedent = $1 || return; my @dependents = split(/,/, $cpstring); my @cptrequest = ($antecedent, \@dependents); push @{$runconfig{"cp"}},(\@cptrequest); }
    not particularly complex - but there are a number of these functions that i call. and do i want them littering the call to GetOptions, where they not only look ugly, but prevent me breaking at them easily in my debugger?

    not really. if i were to implement all those functions anonymously, it would get to be a real mess there in GetOptions, and i would lose substantial brownie points if my grandmother took it into her head to look at the code. i mean, it's just not very neat and not very functional either, when it comes to debugging.

    now you may object that your scripts are rarely as complex as the above, and it looks nicer. but i would say that from a defensive coding perspective, you'd be better using real subs. if your script is a worthy brainchild, you will use it more, and want to see it grow. give it the room it needs!

    ...wufnik

    -- in the world of the mules there are no rules --
      To cut it short you mean: "It gets confusing if you overuse these anonymous subs", right?

      I do not intend to use any other sub than help as anonymous. I love to have the help text at the very beginning of my scripts, because you see the help as soon as you look into the script.
Re: Getopt::Long good style?
by xtype (Deacon) on Jul 28, 2004 at 16:42 UTC
    For what it is worth, here is some GetOpt_Long code that I recently used:
    use strict; use Getopt::Long; use Pod::Usage; my $verbose = 0; my %opts = ('verbose' => \$verbose); GetOptions(\%opts, ## throw our options into a hash "infile=s", ## incoming mbox file "offset=i", ## seek position (in bytes) "logfile=s", ## file to log into "onerun!", ## only read the first message "maxrun|max=i", ## maximum number of messages to read "verbose+", ## set verbosity level "finduser!", ## attempt to perform user lookup. "nslookup!", ## attempt to perform nslookup for zone ... slo +w "help|?", ## prints usage message. "man", ## prints entire POD. ) or pod2usage(0); pod2usage(-verbose => 2) if exists $opts{man}; pod2usage(-verbose => 1) if exists $opts{help}; pod2usage(-msg => "missing infile: --help for more information", -verbose => 0) unless exists $opts{infile}; etc, etc
    ...and then my POD has a SYNOPSIS and an OPTIONS AND ARGUMENTS section.
    I, like naChoZ, prefer the use of an options hash. It makes it easier when I need them in a subroutine I can just pass a reference to that hash.

    The Getopt::Long POD suggested the use of Pod::Usage.

    -xtype
Re: Getopt::Long good style?
by Aristotle (Chancellor) on Jul 28, 2004 at 16:32 UTC

    I don't have much to say myself, because others have done so before me:

    You might want to peruse Super Search next time before posting a question like this… :-)

    Also, I'd advise against using a hash with Getopt::Long. It looks tidier, but you lose the advantage of strictures — the only clue that you misspelt a hash key is odd behaviour from the script. Instead, use my variables (and declare them in-place, as per above link), and use strict, so that Perl will find your typos for you.

    Makeshifts last the longest.

      I'd love to use Super Search for questions like this. But tell me: If you were in my shoes? What would you have searched for? I had no clue what to search. Please show me what I would have found and how it should have answered my question.
        Cutting and pasting the title of the OP itself turns up useful nodes like 241367.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://377971]
Approved by ccn
Front-paged by ccn
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (4)
As of 2024-04-20 01:31 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found