Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A6: Named vs. Variadic Parameters

7 views
Skip to first unread message

Michael Lazzaro

unread,
Mar 14, 2003, 7:23:30 PM3/14/03
to perl6-l...@perl.org
A simple question, I hope...

From A6, "Calling Subroutines", comes the following:

multi push(@array, +$how, *@list) {...}

push(@a, how => 'rapidly', 1,2,3); # OK
push(@a, 1,2,3); # WRONG, $how == 1!

Oops! What you really wanted to say was:

multi push(@array, *@list, +$how) {...}

push(@a, how => 'rapidly', 1,2,3); # OK
push(@a, 1,2,3); # OK

Note the gotcha part... if you want to use both named arguments and a
variadic list, you must declare the parameters in the signature in a
different order than they must appear when actually calling the sub.
If you put the signatured params and the actual arguments in the _same_
order, it will break. The reason for this is because, in the first
example, the slurpy array has been placed in the named-only zone, _not_
the positional zone.

Clearly, it's going to be a newbie problem, and I guess I'm not
understanding why we can't enforce What They Really Meant.

When calling a sub that has both named params and a slurpy list, the
slurpy list should always come last. If a sub has both a slurpy hash
and a slurpy list, the slurpy list should still always come last. You
simply can't credibly have anything after the slurpy list, or it'll be
slurped. So args/params must ALWAYS come in this exact order, if they
are to be useful:

sub foo(
$x, # required positional
?$y, # optional positional
+$k, # optional named
*%h, # optional slurpy hash
*$s, # optional slurpy scalar
*@a, # optional slurpy array
) {...}

I guess what I'm not understanding is why you would _EVER_ want *@list
to be in the named-only zone, and presuming you never would, why we
can't syntactically / semantically fix the above gotcha so that the
params always appear in the "calling" order?

MikeL

Luke Palmer

unread,
Mar 14, 2003, 7:26:42 PM3/14/03
to mlaz...@cognitivity.com, perl6-l...@perl.org
> When calling a sub that has both named params and a slurpy list, the
> slurpy list should always come last. If a sub has both a slurpy hash
> and a slurpy list, the slurpy list should still always come last. You
> simply can't credibly have anything after the slurpy list, or it'll be
> slurped. So args/params must ALWAYS come in this exact order, if they
> are to be useful:
>
> sub foo(
> $x, # required positional
> ?$y, # optional positional
> +$k, # optional named
> *%h, # optional slurpy hash
> *$s, # optional slurpy scalar
> *@a, # optional slurpy array
> ) {...}
>
> I guess what I'm not understanding is why you would _EVER_ want *@list
> to be in the named-only zone, and presuming you never would, why we
> can't syntactically / semantically fix the above gotcha so that the
> params always appear in the "calling" order?

The idea is that positional parameters are always a contiguous
sequence in the argument list. If it looked like this:

sub foo($x, ?$y, +$k, *@a) {...}

Then one might presume to call it like:

foo($x, $y, $k, 1, 2, 3);

Which they can't. So it makes sense to have everything positional up
front, while things that can go anywhere (but must be labeled) in the
back.

Your method makes sense, too. To me, they both make a lot of sense,
but they aren't orthogonal. So you have to pick one. I'm happy with
the current way.

Luke

Mlazzaro

unread,
Mar 15, 2003, 9:46:21 PM3/15/03
to Luke Palmer, perl6-l...@perl.org
Luke Palmer wrote:

> The idea is that positional parameters are always a contiguous
> sequence in the argument list. If it looked like this:
>
> sub foo($x, ?$y, +$k, *@a) {...}
>
> Then one might presume to call it like:
>
> foo($x, $y, $k, 1, 2, 3);
>
> Which they can't. So it makes sense to have everything positional up
> front, while things that can go anywhere (but must be labeled) in the
> back.

I guess. The most confusing part is this:

sub foo($x, +$k, *@a) {...} # (1) WRONG
sub foo($x, *@a, +$k) {...} # (2) OK

sub foo($x, +$k, *%h) {...} # (3) OK(?)
sub foo($x, *%h, +$k) {...} # (4) WRONG(?)

Not only are (1) and (4) wrong, but they're always wrong... AFAICT, there's
no possible way to get $k correctly if you use those two forms. (Or maybe
it's (1) and (3) that are wrong, or maybe both (3) and (4) are OK and only
(1) is wrong; it depends on whether *%h is considered 'positional' or
'named'. I'm not even remotely sure.)

So I would emphatically hope that (1) and (4) produce compile-time errors,
at minimum. If we wanted to silently accept (1) and (4) as synonyms for
(2) and (3), that would be OK too.

But PLEASE, PLEASE make them compile-time errors if they aren't going to
work!

MikeL

Larry Wall

unread,
Mar 19, 2003, 12:58:39 PM3/19/03
to perl6-l...@perl.org

Depends on what you mean by "work". Those are all perfectly good
declarations. But only (2) allows you to tack the slurpy list
positionally to the end of the positional parameters.

: sub foo($x, +$k, *@a) {...} # (1) WRONG

Not wrong. It says you must set $k using named notation. If you
want a list, it goes after "k => $x". If you don't want to pass k,
you should use <== to mark the variadic transition. (I suspect some
style guides will require <== on all list operators. Something to
be said for that.)

: sub foo($x, *@a, +$k) {...} # (2) OK

Fine, you can set @a using positional notation, like push(), in
addition to the notations available to (1). But if you set "k =>",
it has to be before the list, unless you pass the list explicitly as
a "*@" named parameter. With the exception of *@a at the front as
in (2), non-positional parameters don't pay any attention to their
order of declaration.

: sub foo($x, +$k, *%h) {...} # (3) OK(?)

Says bind "k => $x" to $k, then put any other named parameters in %h
(and maybe k's pair too, depending on implementation).

: sub foo($x, *%h, +$k) {...} # (4) WRONG(?)

Says exactly the same as (3). Non-positional parameters don't care
what order they're declared.

Larry

Michael Lazzaro

unread,
Mar 19, 2003, 3:19:20 PM3/19/03
to Larry Wall, perl6-l...@perl.org
On Wednesday, March 19, 2003, at 09:58 AM, Larry Wall wrote:
> : sub foo($x, *@a, +$k) {...} # (2) OK
>
> Fine, you can set @a using positional notation, like push(), in
> addition to the notations available to (1). But if you set "k =>",
> it has to be before the list, unless you pass the list explicitly as
> a "*@" named parameter. With the exception of *@a at the front as
> in (2), non-positional parameters don't pay any attention to their
> order of declaration.

It's the "with the exception of *@a at the front" part that worries me
quite a bit. I'd be a lot happier with having the rule be
"non-positional parameters must come after positional parameters, but
before any variadic elements".

I think newbies are going to unquestionably try and put the parameters
in the same order as they expect to see the eventual arguments, and be
durn confused it doesn't work -- I know I would. Especially because:

sub foo($x, +$k, *%h) {...} # (3)

sub foo($x, *%h, +$k) {...} # (4)

_are_ synonymous, but

sub foo($x, +$k, *@a) {...} # (1)

sub foo($x, *@a, +$k) {...} # (2)

are quite definitely not.

Dunno. I'm just one datapoint, but I strongly see the difference
between (1) and (2) as being a *huge* newbie trap. And it doesn't seem
like you ever gain anything by specifying (1) -- I don't know why you
would ever purposefully _want_ to do that, instead of (2). So I would
still strongly urge that (1) and (2) be synonyms.

MikeL

0 new messages