We've seen many problems come up with the current special treatment of
pairs.  Here's what I can think of:

* Pairs are restricted to a particular position in the argument list, which 
    leads to confusion (why isn't this being passed named?) and poor
    end-weight in something like this:

    foo {
       # lots of code in here
       # blah blah blah
       ...
    } :delay(1)

    which would probably be more readable with :delay(1) up at the top

* We had to special-case pointy blocks not to take named arguments because 
    of this construct:

    for %hash.pairs -> $pair { ... }

* (IIRC) We still have to scan potentially infinite lists when using the
    foo([EMAIL PROTECTED]) caller-side flattening form.

I propose that we move the magic out of the Pair type, and into a
syntactic form.  Here's the best we have (from #perl6) at the moment:

    a => b        # always a plain-vanilla pair, never a named argument
    :a(b)         # always a named argument (in sub calls)
                  # degenerates to a plain pair when not in a sub call
    named(a => b) # make an ordinary pair (or list of pairs) into 
                  # runtime named arguments
    named(%named) # same

This has a couple of advantages.  First of all, in the call:

    foo($a, $b, $c)

You *know* that you're passing three positionals.  It looks like what
it is.  Also, you don't have to take extra cautionary measures if
you're dealing with generic data.

It's much less work for the runtime.  You don't have to scan for
pairs, you just have the caller stuff them where you need them.

You only lose a *little* bit of flexibility at a great gain of
usability of pairs.  That little bit is this ability:

    my @args = (1, 2, 3, foo => 'bar');
    baz([EMAIL PROTECTED]);   # $foo gets argument 'bar'

And yet, you can fudge that back in on the callee side:

    sub baz ([EMAIL PROTECTED]) {
        my (@pos, %named);
        for @args {
            when Pair { $named{.key} = .value; }
            default   { push @pos: $_ }
        }
        real_baz([EMAIL PROTECTED], named(%named))
    }

And you lose the ability to pretend that you're taking named arguments
when you're not; that is, you say you're not being order dependent
when you are.

I think this is fixable with a trait on the sub:

    sub form ([EMAIL PROTECTED]) is unnameable # refuse named parameters 
altogether
    { }

Anything more magical than that can be dealt with explicitly.

Luke

Reply via email to