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

PDD 03 Issue: keyword arguments

14 views
Skip to first unread message

Sam Ruby

unread,
Nov 30, 2004, 10:29:17 PM11/30/04
to perl6-i...@perl.org
Python provides the ability for any function to be called with either
positional or keyword [1] arguments. Here is a particularly brutal example:

args={'a':1,'b':2,'c':3}
def f(a,b,c): return (a,b,c)
def g(b,c,a): return (a,b,c)
for j in [f,g]: print j(1,2,3)
for j in [f,g]: print j(a=1,b=2,c=3)
for j in [f,g]: print j(*args.values())
for j in [f,g]: print j(**args)

I see nothing in pdd 03 that provides any guidance as to how to handle
this. What makes this issue so critical is that any solution will
potentially affect *every* function.

- Sam Ruby

P.S. Jython handles the above test correctly. Iron-Python handles all
but the **args properly.

[1] http://docs.python.org/ref/calls.html

Sam Ruby

unread,
Dec 1, 2004, 10:07:29 AM12/1/04
to perl6-i...@perl.org
Sam Ruby wrote:
> Python provides the ability for any function to be called with either
> positional or keyword [1] arguments. Here is a particularly brutal
> example:
>
> args={'a':1,'b':2,'c':3}
> def f(a,b,c): return (a,b,c)
> def g(b,c,a): return (a,b,c)
> for j in [f,g]: print j(1,2,3)
> for j in [f,g]: print j(a=1,b=2,c=3)
> for j in [f,g]: print j(*args.values())
> for j in [f,g]: print j(**args)
>
> I see nothing in pdd 03 that provides any guidance as to how to handle
> this. What makes this issue so critical is that any solution will
> potentially affect *every* function.

Upon sleeping on it, a potential solution came to me. There actually
are multiple, related, problems: positional arguments, keyword
arguments, defaults, passing arguments in a list expression, and passing
arguments in a dictionary expression.

What Parrot defines is a mechanism to define and call a subroutine with
a variable number of positional arguments. So, we will focus on making
that subset interoperable. Everything else is - by definition - Python
specific.

When compiling the function itself, you know the names, positions,
number of arguments, and any defaults that may be provided. Functions,
themselves, are PMCs, so names a defaults can be stashed into
properties. Code to check the number of actual parameters and to fill
in missing ones with defaults will need to be emitted. Net cost: a
small one time cost of saving keywords in all cases, and a small
overhead for defaults that only occur when they are actually defined
and/or used.

When compiling a call to a function, you know the number and positions
of the actual arguments, as well as optionally a set of keyword and
expresions. If only positional arguments are used, then Parrot standard
calling conventions are to be used, and everything just works, including
defaults.

If keyword arguments are used, then a completely separate interface is
required. This will be provided by the __call__ method, which takes two
arguments: a list of arguments and a dictionary of keyword/value pairs.
The __call__ method can enforce all of the python semantics for
binding arguments.

The merits to this approach is that interoperability and performance are
only impacted to the extext that given features are used.

- - -

Comments welcome. The question Parrot needs to answer is whether
keyword arguments should be a part of the interoperable core (register
P4 looks very tempting ;-)), or are a language specific extension.

- Sam Ruby

Dan Sugalski

unread,
Dec 1, 2004, 10:14:55 AM12/1/04
to Sam Ruby, perl6-i...@perl.org
At 10:29 PM -0500 11/30/04, Sam Ruby wrote:
>Python provides the ability for any function to be called with
>either positional or keyword [1] arguments. Here is a particularly
>brutal example:

Oh, it's even more brutal than that. Perl 6 goes one step further,
such that you can't tell whether a name/value pair is a keyword or
positional parameter at the time you make the call, and can
potentially be either with MMD. (There's a reason I've been hiding
from this one) Each potential keyword parameter is a name/value pair
(of type Pair), but whether it's to be taken as a keyword fillin or a
positional parameter depends on the called sub. For example:

foo(b => 1, a=> 2)

is a keyword call if foo's prototype is:

sub foo($a, $b)

or

sub foo(Integer $a, Integer $b)

but is a positional call if the prototype is:

sub foo(Pair $a, Pair $b)

and if the prototype is

sub foo(Pair $a, Integer $b)

I think I get to smack someone with a stick.

Anyway, this is... complex, or at least hurts my brain, but it's time
to deal with it.

My first thought is this scheme:

All potential keyword parameters (that is, name/value pairs) are
passed in as PMCs of type Pair. (Pairs will need to have some sort of
funky vtable to allow them to act mostly like their value, I think,
to make this work right) The called sub, if it cares to do named arg
parsing, will then go process the passed in parameters and Do The
Right Thing with them, presumably stuffing values into the right
spots and yelling if things aren't right.

It feels like something of a cheat, but I'm OK with cheating with
this if we set up the right protocol and provide support for it.
(Like some sort of library routine or opcode to handle shuffling the
keyword parameters into the right spots, and we probably ought to
have it provide optional typechecking while we're at it)
--
Dan

--------------------------------------it's like this-------------------
Dan Sugalski even samurai
d...@sidhe.org have teddy bears and even
teddy bears get drunk

0 new messages