Parsing Command Line Arguments in Perl 6

Like many people, I do a lot of automation using Perl. Years ago I began making utilities more generalized than specific, so I could re-use them in slightly different situations.

This means using a lot of command line arguments passed to Perl so that it knows what to do. Always in Perl 5 I used Getopt::Long to parse command line parameters – a truly great module that was always there. Not so with Perl 6 – some very good command line argument parsing is built in.

The MAIN Subroutine

The key is discovering that Perl 6 supports the use of a subroutine named “MAIN” which is called whenever you run a Perl 6 program, much like a C program. The command line arguments can be captured and processed in the definition of the MAIN subroutine.

For example, say you were writing a utility to crop an image. You want to be able to call it like

cropimage --top=10 --bottom=15 --left=50 --right=30 picture.png

In Perl 6, this is all you would need to do:

#!/usr/bin/env perl6

sub MAIN ( $filename,
           :$left, :$right,
           :$top,  :$bottom ) {

    say "$left $right $top $bottom $filename";
}

Variables get automatically defined in the MAIN scope, so you don’t have to use “my”. And if you put a colon “:” before the variable name, Perl will treat that as a named parameter. Notice how $filename doesn’t have a “:”? So we don’t have to put a named parameter in the command line.  But the other variables have “:”‘s before their names, so that means they have to be a named parameter.

Worth noting as well that Perl seems to like having the non-named parameters come before the named ones in the sub MAIN definition. In other words, positional ones come first, then do named ones.

Optional and Required Parameters

If you want to make a parameter required, shout it and put an “!” after it’s name. If you want it to be optional, put a “?” after it:

sub MAIN ( :$left!, :$right?,  ....

would mean that the named parameter –left MUST be supplied or Perl will generate an error for the user, while the –right parameter is optional.

Parameter Default Values

Now, with our example, we may not need all of the parameters every time, so they should be optional. But we will also want to have default values of 0, since when the parameters are not specified, we’ll want to crop 0 pixels off in that direction.

So lets make all of our parameters optional and with a default value of 0. Of course, parameters with default values are always optional. It’s just a matter of setting an equality in the MAIN definition:

#!/usr/bin/env perl6

sub MAIN ( $filename,
           :$left = 0, :$right  = 0,
           :$top  = 0, :$bottom = 0 ) {

    say "$left $right $top $bottom $filename";
}

With this, we’ll get actual 0’s coming out in our “say” 😉 even if we pass in no parameters but $filename.

Constraining Parameters into Sanity

You know there will always be some smart aleck or some universal happenstance that will throw wrenches at you. It’s the curse of being our own form of order within other’s entropy. Take for example the guy who wants to crop 10.88242 pixels in on the left. Yeah, that guy.

This is where Perl’s variable type system can help. There are LOTS of types available. We’ll keep this simple. In our case, we don’t want to slice up our pretty monitor’s pixels into .88242 segments. We want whole pixels or nothing! An integer, in other words.

To constrain parameters to a type, just place the type name before the variable/parameter definition. You don’t have to, of course, but if you choose to, it can help sometimes.

#!/usr/bin/env perl6

sub MAIN ( Str $filename,
           Int :$left = 0, Int :$right  = 0,
           Int :$top  = 0, Int :$bottom = 0 ) {

    say "$left $right $top $bottom $filename";
}

But you know they’ll be right back, breaking it again, because they thought it would be cute to crop a negative amount of pixels from the image. So maybe you’d want to use the UInt type instead (Unsigned Integer) so the value will have to always be positive.

Another useful thing is specifying a type Bool for a parameter variable, which basically makes it into a flag.

Oh, did I mention you can use dashes “-” in variable names in Perl 6? That amazed me, along with the fact you can use full UTF8 charactersets.

So suppose we wanted to be able to specify an optional output filename for our cropped image.  We’d like something like this to work:

cropimage --left=25 --output-file=cropped.png filename.png

All we have to do is call the named parameter variable $output-file and make it optional.

#!/usr/bin/env perl6

sub MAIN ( Str $filename,
           Int :$left = 0, Int :$right  = 0,
           Int :$top  = 0, Int :$bottom = 0,
           Str :$output-file? ) {

    say "$left $right $top $bottom $filename";

    say "Writing " ~ ($output-file || $filename);
}

Bonus Error Messages!

If you tried any of these and got an error, you’ll see how nicely Perl formats these when you’re using the built-in parameter handling. It’s an actual detailed “Usage:” description that is given to the end user, detailing all the parameters and their types. Very Cadillac. 🙂

Installing Perl 6 on Debian or Ubuntu

Keep in mind, this is written on 09-Sep-2016 and updated on 01-July-2017 – stuff can change over time.

Perl 6 is developing rapidly, specifically, the MoarVM and Rakudo which comprise the environment that implements the Perl 6 specifications.

Every Linux distribution comes with Perl. Many have Perl 6 now as well. With Perl 6’s rapid development, these distribution packages of Perl 6 can be outdated.

This is how I installed Perl 6 in Ubuntu and Debian. We rely on a system much like Perlbrew, called Rakudobrew to automatically download and compile the necessary stuff for us, and change our environment to be able to find perl6

Git Your Compile Tools

First, you need to be certain you have the tools and libraries necessary to compile stuff on your local machine.

apt-get install build-essential git libssl-dev

This will install the gcc compiler and various libraries along with the git version control system so we can download the latest rakudobrew and keep up to date over time.

Download and Install Rakudobrew

git clone https://github.com/tadzik/rakudobrew ~/.rakudobrew
echo 'export PATH=~/.rakudobrew/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

The first line uses git to download the rakudobrew archive into your home directory in .rakudobrew. No biggie. These instructions are taken (mostly) directly from the Rakudo site.

The second line alters your shell environment PATH to include this directory’s “bin” subdirectory. This is wildly dangerous unless you trust absolutely where you are downloading from, which is never a good idea. You can always just compile it yourself if you follow the instructions on the above-linked Rakudo site.

The third line alters your currently-existing PATH in your terminal to add that .rakudobrew/bin directory (you could also close your terminal and open a new one instead).

Have Rakudobrew Compile Rakudo and MoarVM

This bit’s the easy part now, thanks to Rakudobrew.

rakudobrew build moar
rakudobrew build zef

The second line builds and installs Zef, which is Perl6’s cpan or cpanm tool for module installation — as the docs say: “It’s like [cpanm] wearing high heels with a tracksuit”.

How to Run a Perl 6 Program

Easy enough if you’ve done the bit above to include .rakudobrew/bin in your shell path. You can just type “perl6” and have an interactive interpreter to play around with.

Or if you prefer to edit a file, you can run the file with

perl6 filename

Tough, eh? Or if you’d rather the OS knows to do perl6 for you, give it that magic hashbang at the top of the file like so

#!/usr/bin/env perl6
my $code = "about normal";say "I know nothing " ~ $code;
("I know nothing" ~ $code).say;
say "The new $code";

No need for warnings. No need for use Modern::Perl . No need for strict, Try::Tiny, etc.

There ya go!

Perl 6 First Impressions

Perl Camelia LogoStarting at the beginning in Perl6, I had no clue. I only have a slight one now. But I’ll be documenting some of the things I learn in subsequent posts, in case it can help anyone in the future.

This first post will be about initial impressions, coming from someone who knows a bit about earlier Perls, and has held off actually putting Perl 6 into work.

Background Info

Perl now runs via a VM – right now either the standard JVM or a new one called MoarVM (which people seem to like best and is default, and which I like too because it hasn’t hurt me yet).

Perl itself is a language specification. It relies on the Rakudo compiler to implement that language specification and tie it into MoarVM. This is a great separation of concerns — MoarVM can worry about interacting with the operating system, Rakudo can worry about what it needs to tell MoarVM to do and what the heck a Perl coder meant to happen, while Perl itself remains only in the abstract.

Why Use Perl6 when Other Languages Work Great?

For me it was curiosity. I love coding in Perl, for the most part. It’s the most flexible and powerful language I’ve encountered. I’ve been curious about Perl6 for years, but resisted putting any of it into production until recently. There’s something about it now that feels solid and ready. Here are some of the things that feel compelling to me right now.

Close to the OS

One of the several reasons I reach for Perl before any other language is because it runs close to the OS. Perl grew out of shells and shells grew out of Perl. I was worried I might lose this with Perl6. So far, I am very happily surprised. There is much that makes interacting with the shell/OS even easier – things that don’t require finding the module du jour and reading or refreshing up on it. It just flows in and out of the language.

Bondage or Freedom

It’s your choice! Perl has traditionally been very flexible, and many people who like to be told exactly what to do, or like to tell others exactly what to do — these people become easily exasperated by the freedom of expression Perl offers.

Eventually Perl modules were created that acted like tight girdles and cat-o-nine-tails upon those people, to help satisfy them. Now Perl6 has its own build-in dungeon basement!

You don’t have to use it though. But it’s there if you want it, and it’s seamlessly part of everything.

For example, you can enforce variable types if you want to, and a great many of them too, in bizarrely interesting ways. And you can coerce them around. Or you can leave everything all free-form.

You can use positional parameters when calling methods or subroutines, enforce types there too, or use named parameters, or just sloppily slurp in data. (or neatly slurp 😉 )

And there are many ways to die, even in an orderly way with exceptions. And the default error messages are pretty great, most of the time, with calling stacks included by default, without having to use modules.

And control structures… well, there’s a veritable zoo. Or just your standard, well-known tried and true for those who shrink at variety.

Perl is Smart

Perl has never been limited to being discreetly-sized Lego blocks that kids can easily make a toy house from. It can be used that way, of course. And often it is, by people new to the language.

For me, Perl’s greatest strength is that it has always allowed me to work very intimately with the structure, flow, manipulation and presentation of data, in whatever form, as an actual capability built into the language itself — and to accomplish it in ways that are both optimal and intuitive.

These capabilities have only increased with Perl6 as far as I have seen, though some semantics for getting there have changed. But those changes I believe are justified because I can see how they make sense, to give room to other capabilities that have been added, and to provide some clarifications.

In case that doesn’t make sense, one little example is that string concatenation is no longer done with a dot “.”. In Perl6, variables (objects) can have a dot after them to call a method on that object — that could potentially get confused with a concatenation dot. So they’ve made the concatenation into a tilde “~” instead. It actually looks better I think, but it was a nightmare to figure out when first starting to play. I’ll be documenting some more gotchas as I run across them.

BTW – that last change mentioned also influences other things. For example, “$string .= $thing” has become “$string ~= $thing” for concatenation.

What Sucks about Perl 6

Oh my god everything! (I thought at first). I really did. And I kept running into problems and errors that naturally were due to Perl6’s newness breaking it, and not my own ignorance…. but of course, like most ignorance, it doesn’t recognize itself — and it turns out that every time I thought I had found a bug in Perl6, it was really me not understanding how something had changed, and why.

I may run into legitimate bugs at some point though! I’m just now starting to really dive in. But they’ve had a very long time to work through things.

But it does suck that there are odd little differences between Perl 5 and Perl 6 here and there that can cause problems. But that’s the nature of change. So far nothing sucks really, once I move aside my own irritation at having to learn a few new things.

What’s Surprising about Perl 6

What surprises me most about Perl 6 is that Larry and the team have managed to preserve so much of what was truly monumentally great about Perl 5 and bring that into a context that is offering so many conveniences that were previously only attainable by using sometimes kludgey modules.  For example, I love how we handle command line arguments now. I’ll get into that. No more real need for stuff like Getopt::Long for most things.

Also I had heard that Perl 6 takes a long time to start up and actually run something. This is not the case, at least any more. It feels pretty instantaneous so far, and considering that it has the functionality of Moose built in, that’s awesome! 🙂

I haven’t done any performance metrics on it, and don’t really plan to.  Well, maybe. But it has been a lot more fun than I imagined, and I’m actually looking forward to stopping writing this and getting back to more using it.

Another thing that is surprising to me is its handling of numerics — the math is damn good, and you don’t get weird rounding errors from what I’ve seen. Also it has these magical ranges of numbers that can go clear up to infinity, or skip in defined sequences, and has even type testing built in like is this number a prime… ?

What’s surprising is that it feels like it’s a whole magical world again, and one where you can use convention, or establish your own conventions just as easily.

Anyway, I’ll leave this at that. I’ve really only taken the first little test drive, and not put it through an real industrial rigors. That will be coming as I gain deeper familiarity with Perl 6 — which I have decided now, I intend to do.

Perl Major Mode for Emacs – How to Install

If you are an emacs user and the normal Perl mode is not formatting your newfangled Perl6 code properly, you may need a different mode than perl-mode.

Thanks to Hinrik Örn Sigurðsson you can get an Emacs major mode called perl6-mode from Github. And if you’re lazy like me, you’ll probably just want to have Emacs install and compile it for you from the MELPA archive.

To do that, in your .emacs file put:

(require 'package)
(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))

This will allow you to download emacs packages/modes from the MELPA archive for Emacs. Then in Emacs do a:

M-x package-refresh-contents
M-x package-install
perl6-mode

From that point on, emacs should recognize Perl6 by file extensions or even if you have the magic headers like #!/usr/bin/env perl6 at the top of your programs.

So far, I’ve found Hinrik’s perl6-mode to be a godsend — I was going nuts living with the perl-mode getting confused. The only thing I’ve noticed is that it doesn’t colorize pod stuff the way I’m used to.

Thank you Hinrik!!!