Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
severely restrict named-to-positional binding
Binding named args to positional parameters is now restricted to
explicit C<proto> and C<only> declarations.  But we will support it,
since it can have profound refactoring advantages if you don't have
to know which parameters will eventually end up as positionals.
  • Loading branch information
TimToady committed Jun 30, 2011
1 parent e881c78 commit 94d0124
Showing 1 changed file with 59 additions and 14 deletions.
73 changes: 59 additions & 14 deletions S06-routines.pod
Expand Up @@ -16,8 +16,8 @@ Synopsis 6: Subroutines

Created: 21 Mar 2003

Last Modified: 5 Jan 2011
Version: 148
Last Modified: 30 Jun 2011
Version: 149

This document summarizes Apocalypse 6, which covers subroutines and the
new type system.
Expand Down Expand Up @@ -988,18 +988,63 @@ bound. Named optional parameters default to C<Nil> if they have
no default. Named required parameters fail unless an argument pair
of that name is supplied.

Bindings happen in declaration order, not call order, so any default
may reliably depend on formal parameters to its left in the signature.
In other words, if the first parameter is C<$a>, it will bind to
a C<:a()> argument in preference to the first positional argument.
It might seem that performance of binding would suffer by requiring
a named lookup before a positional lookup, but the compiler is able
to guarantee that subs with known fixed signatures (both C<only>s and
C<proto>s) translate named arguments to positional in the
first N positions. Also, purely positional calls may obviously omit any
named lookups, as may bindings that have already used up all the named
arguments. The compiler is also free to intuit proto signatures for
a given sub or method name as long as the candidate list is stable.
Bindings logically happen in declaration order, not call order, so
any default may reliably depend on formal parameters to its left in
the signature.

Another benefit of this policy is that, for routines that allow it,
named arguments may be bound to positional parameters. (This is
allowed only on routines that are I<explicitly> declared with either
the C<proto> or the C<only> declarator.) If the first positional
parameter is named C<$a>, for example, it will bind to a C<:a()>
argument in preference to the first positional argument.

The restriction to explicit C<proto> and C<only> declarations is
motivated by the desire for both API purity and efficiency. Normal
C<multi> or C<sub> declarations and normal method declarations do not
attempt to look for named bindings to positionals. At most there is
one such binding for any dispatch, when it initially calls the C<proto>
(or explicit C<only>). The C<proto> binder (for either sub or method)
must automatically remap such named parameters to positionals before
calling its internal multi dispatcher (the one represented by C<{*}>).
In the case of a C<proto> sub, this mapping can be done at the point
of the call, since there can only be one possible set of positional
names, and the proto to be called can be known at compile time (in
the absense of CANDO declarations in the outer scopes). So after

proto foo ($x, $y, :$bar, :$baz) {*}
multi foo ($a, $b, :$bar, :$baz) {...}
multi foo ($n, $m, :$bar, :$baz) {...}

foo :y(2), :x(1); # can turn into foo(1,2)

the call to C<foo> can be turned into a pure positional call to
the C<proto> (which can in turn be inlined because it's using the
standard C<{*}> dispatcher--and likewise for methods, when the class
containing the C<proto> is known to be finalizable). Note also that
multi definitions are never required to use the same parameter names
for positional parameters, since after the C<proto> binding is done,
the names (if any) are never used again for positionals.

The C<$x> and C<$y> names above are part of the public API only
because they are named in the C<proto>. Positional parameter names
are never part of the advertised API unless explicitly enabled.
An explicit C<proto> may easily refrain from advertising names by
declararing positionals with bare sigils:

proto foo ($, $, :$bar, :$baz) {*}
multi foo ($x, $y, :$bar, :$baz) {...}

foo :x(1), :y(2); # illegal

(And an C<only> routine may control the positional API simply by
using C<sub> instead, or by defining a C<proto> with a single C<multi>
if finer control is desired.)

It follows from all this that an intuited proto never has to worry
about supplying the API names of positional parameters. And no proto
ever has to worry about conficting names in the positionals of the
multis they dispatch to, since any remapping is handled before that.

=head2 List parameters

Expand Down

0 comments on commit 94d0124

Please sign in to comment.