Something cool about Perl 6 every day

Primary Menu

Day 9: Having beautiful arguments (and parameters)

On the ninth day of advent, we unwrap… the syntax for parameters and arguments.

You may or may not be familiar with the way Perl 5 does parameter handling in subroutines. It goes something like this:

sub sum {
[+] @_
}
say sum 100, 20, 3; # 123

The [+] is Perl 6, but we might as well have written that as my $i = 0; $i += $_ for @_; $i, and the above would have worked in Perl 5. The important point is that, in Perl 6 as well as in Perl 5, when you call a subroutine, your parameters can be found in @_. You unpack them, and you do your thing.

This system is extremely flexible, because it doesn’t impose any mechanism on the handling of parameters; it’s all up to you, the programmer. It’s also tedious, and favours boilerplate to some extent. Take this fictional example:

One feature I particularly like is that you can refer to the parameters by name when calling, passing the named arguments in any order you like. I can never remember the parameter order in functions like this:

The colon means “here comes a named argument”, and the whole construct is to be read as :name_of_parameter($variable_passed_in). There’s a short form that can be used when the parameter and the variable happen to have the same name, though:

If you, as the API author, want to force people to use named arguments — which might actually be appropriate in the case of draw_line — you need only supply the colons in the subroutine signature.

sub draw_line(:$x1, :$y1, :$x2, :$y2 ) { ... } # optional nameds

But be careful, named arguments are optional by default! In other words, the above is equivalent to this:

sub draw_line(:$x1?, :$y1?, :$x2?, :$y2?) { ... } # optional nameds

If you want to explicitly make parameters required, you can append a ! to them:

sub draw_line(:$x1!, :$y1!, :$x2!, :$y2!) { ... } # required nameds

Now the caller has to pass them, just as with ordinary positional parameters.

What about varargs? Say you want an arbitrary number of arguments passed in. No problem: just make the parameter an array and precede it with a *:

sub sum(*@terms) {
[+] @terms
}
say sum 100, 20, 3; # 123

I use the same example as we started out with to make a point: when you don’t supply a signature to your subroutine, what you end up with is the signature *@_. This is the signature that emulates Perl 5 behaviour.

But an array with a * in front of it (a ‘slurpy array’) only captures positional arguments. If you want to capture named arguments, you’d use a ‘slurpy hash’:

There are two chief reasons for making parameters readonly; one being efficiency. Optimizers like when variables are read-only. The other reason has to do with encouraging the right habits in the programmer, and make it slightly more cumbersome to be sloppy. Functional programming is good not only for the optimizer, but for the soul as well.

11 thoughts on “Day 9: Having beautiful arguments (and parameters)”

but it is worth mentioning that this also serves another purpose, as it SHOULD croak on increase_by_one(42). ie. the rw should constrain the parameter to non-constant things. sadly rakudo still fails this one (or at least last time i checked).

The short form of named arguments is really, really nice. Not least because it interacts seamlessly with twigils (by ignoring them) — something that only becomes a desired feature after a while, when you suddnely think “hm, will it work if I do this? It cannot possibly work if I do this…” …and it does!

I think the point where I really fell in love with the short form of named parameters was when I realized that they can be used even with variables that have a twigil (secondary sigil) — for the purposes of the parameter naming, it’s simply ignored. So these examples all work:

Oops, that was a thinko on my part — the &action does need to be specified. Now corrected in the post. Thanks.

A few random comments: a Perl 6 compiler with the appropriate presence of mind would flag such an omission at compile time. (There’s no such compiler yet, but it’s definitely possible.) Regardless, the code wouldn’t make it through runtime since the signature binding would fail.

I was once sitting at a dinner table opposite Damian Conway and Larry Wall. Larry was pondering adding a special code-parameter, as in Ruby, with a special syntactic exception so that omission of a comma for a block specified inline would not be an error, as it is now in Perl 6. That idea was just idle speculation, though, and hasn’t made it into spec.