Day 2 – Interacting with the command line with MAIN subs

In Unix environment, many scripts take arguments and options from the command line. With Perl 6 it’s very easy to accept those:

    $ cat add.pl
    sub MAIN($x, $y) {
        say $x + $y
    }
    $ perl6 add.pl 3 4
    7
    $ perl6 add.pl too many arguments
    Usage:
    add.pl x y

By just writing a subroutine called MAIN with a signature, you automatically get a command line parser, binding from the command line arguments into the signature variables $x and $y, and a usage message if the command line arguments don’t fit.

The usage message is customizable by adding another sub called USAGE:

    $ cat add2.pl
    sub MAIN($x, $y) {
        say $x + $y
    }
    sub USAGE() {
        say "Usage: add.pl <num1> <num2>";
    }
    $ perl6 add2.pl too many arguments
    Usage: add.pl <num1> <num2>

Declaring the MAIN sub as multi allows declaring several alternative syntaxes, or dispatch based on some constant:

    $ cat calc
    #!/usr/bin/env perl6
    multi MAIN('add', $x, $y)  { say $x + $y }
    multi MAIN('div', $x, $y)  { say $x / $y }
    multi MAIN('mult', $x, $y) { say $x * $y }
    $ ./calc add 3 5
    8
    $ ./calc mult 3 5
    15
    $ ./calc
    Usage:
    ./calc add x y
    or
    ./calc div x y
    or
    ./calc mult x y

Named parameters correspond to options:

    $ cat copy.pl
    sub MAIN($source, $target, Bool :$verbose) {
        say "Copying '$source' to '$target'" if $verbose;
        run "cp $source $target";
    }
    $ perl6 copy.pl calc calc2
    $ perl6 copy.pl  --verbose calc calc2
    Copying 'calc' to 'calc2'

Declaring the parameter as Bool makes it accept no value; without a type constraint of Bool it will take an argument:

    $ cat do-nothing.pl
    sub MAIN(:$how = 'fast') {
        say "Do nothing, but do it $how";
    }
    $ perl6 do-nothing.pl
    Do nothing, but do it fast
    $ perl6 do-nothing.pl --how=well
    Do nothing, but do it well
    $ perl6 do-nothing.pl what?
    Usage:
    do-nothing.pl [--how=value-of-how]

In summary, Perl 6 offers you built-in command line parsing and usage messages, just by using subroutine signatures and multi subs.

Writing good, declarative code has never been so easy before.

6 thoughts on “Day 2 – Interacting with the command line with MAIN subs

  1. This seems like such a little thing, but for me it’s a killer feature. I write tons of little scripts to automate away busywork. Now it’s development tools, it used to be sysadmin scripts. I either end up not checking input or I have to constantly go back to perldoc and remind myself how to set up Getopt::Long. This and the power of perl6’s prototypes are going to make it a lot easier to whip out little tools by hiding a lot of boilerplate code.

  2. multi MAIN(‘add’, $x, $y) { say $x + $y }
    should probably give usage
    ./calc ‘add’ x y

    If it gives just
    ./calc add x y
    as in the example, ‘add’ might be a variable name?

  3. I have a few questions regarding this feature.

    For example, does
    sub MAIN(Num $x, Num $y)
    provide you with a different usage message?

    Is it possible to distinguish certain alternatives just by using their types? For example will
    multi MAIN(Str $type, Num $x, Num $y)
    multi MAIN(Num $x, Num $y, Num $z)
    work as expected?

    And what about arrays? Does
    multi MAIN(Num @x)
    {
    say [+] @x;
    }
    work as expected?

    I really like this feature of Perl6, I just also would like to know about its limitations.

    1. Currently the type of all arguments (except those that match parameters declared as Bool) are Str, so declaring a sub MAIN with an Int parameter will never do what you mean.

      We know this is not ideal, and are looking for alternative mechanisms. Maybe some smarter type detection for literals would be desirable.

  4. This a really a remarkable feature, the first that makes me go “wow that’s good” in years of lurking.

    At first sight declaring a MAIN in perl seems _so damn wrong_, but given a good look it is _so damn right_ and it introduces first timers to all subroutine argument types fast.

    Very good starting point for tutorials.

    I now ask a minute of silence over Getopt::Long.

    It served us well, and until now it was the best command line parser I had ever had the pleasure to work with, in any language.

  5. Hey, I think your site might be having browser compatibility issues.
    When I look at your blog site in Chrome, it looks fine but when opening in Internet Explorer, it has some overlapping.
    I just wanted to give you a quick heads up! Other then that,
    amazing blog!

Leave a comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.