On Thu, Mar 03, 2005 at 01:03:07AM -0500, Abhijit Mahabal wrote:
: I was thinking about how binding of arguments to parameters in a 
: sub/method call would happen. Seems to be a darn tricky thing with all 
: sorts of potential pitfalls!
: 
: I have a few questions. Consider the following piece of code. Are my 
: expectations correct?
: 
: sub foo($x, $y, *%slurp) { $x + $y }
: say "expecting 10:  ", foo(3,7);
: say "expecting 10:  ", foo(x => 3, y => 7);
: say "expecting 10:  ", foo(y => 7, x => 3);
: say "expecting 10:  ", foo :y<7> :x<3>;

Those should all work.

: my $c = "x"; my $d = "y";
: say "compile time error?:  ", foo($c => 3, $d => 7);

No error, just prevents any compile-time optimization of named arguments.

: say "maybe syntax error? perhaps not  ", foo :$c<3>  :$d<7>;

Syntax error.  Colon pairs only take an identifier after the colon.

: say "run time error?   ", foo(x => 3, y => 7, $c => 5);

Erroneous, I expect, but maybe uncaught.  We do want to allow for
defaults to be passed as a hash:

    foo(x => 3, y => 7, %fallback);

in which case it should take the explicit x or y even if there is
a default value with the same key in the hash.  Likewise, there might
be a list of pairs:

    foo(x => 3, y => 7, @fallback);

That's part of the reason we introduced <==, so that we can pass a
list that starts with pairs without them getting treated as named
arguments.

On the other hand, for a call such as to foo() above, where we know
all the arguments are already specified, we could probably produce
some kind of compile-time warning saying that any extra arguments
will certainly be ignored, much like we give warnings for operations
in void context that have no side effects.

: Similarly, what happens here?
: 
: class foo{
:   has $.x;
:   method bar($.x){} # implicit *%_
: }
: my $f = foo.new;
: my $c = "x";
: $f.bar(10, $c => 5); # runtime error?

Probably just ignored as a default pair viewed through %_.

: Finally, does this also mean that defaults may not be applied until run 
: time? For example:
: sub foo(?$x = 3){...}
: foo($c => 5); # $c may be "x", in which case default not needed.

Yes, in this case you'd have to defer the decision till run time.
The code to do full run-time parameter binding always has to be
compiled in there in any case, since you generally don't know when
someone is going to say foo([EMAIL PROTECTED]) or some such.  The optimizer
just bypasses that code when it thinks it can get away with it.
I'm assuming there will be multiple entry points for a routine,
depending on how much is already known about the arguments.

Also note that all my remarks above are in the context of a single
subroutine definition such as you've given for foo().  As soon as
you start doing MMD, there's very little information available
to the optimizer to do anything but defer to run-time processing,
unless you are in the lucky situation that you can analyze your
entire program with the knowledge that no more routines of a particular
name will ever be added, and all the definitions of multi sub foo
happen to start off with $x and $y.

We could probably set up some way of declaring that a particular
short name must have a signature that is compatible with some
particular base signature in the first N arguments, in which case it
would be illegal to declare a multi-method inconsistent with that.
That's rather draconian, and would basically tend to make certain
modules completely incompatible with each other.  A less violent
way to give information to the optimizer would be to promise that in
your particular lexical scope, you're only interested in definitions
of multi foo that conform to some pattern, and if some other module
defines something else of name foo that doesn't fit your pattern,
it's simply invisible.  Possible we already have those semantics with
the way a set of multies can nest inside a non-multi definition that
hides any multies outside of the non-multi.

In other words, you define a normal sub foo in your outermost lexical
scope that defines the "last" thing a foo can mean, then inside that
you could define or import any multi foo that you like, and keep them
as consistent as you need them to be.  The presence of the outer foo
would tell the optimizer that it doesn't have to pay attention to any
multis you didn't import, and it can then perhaps do some reasoning
if all your multies have $x and $y as the first two arguments,
for instance.

Larry

Reply via email to