compile time signature checking

17 views
Skip to first unread message

Abhijit Mahabal

unread,
Mar 3, 2005, 1:03:07 AM3/3/05
to perl6-l...@perl.org
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>;
my $c = "x"; my $d = "y";
say "compile time error?: ", foo($c => 3, $d => 7);
say "maybe syntax error? perhaps not ", foo :$c<3> :$d<7>;
say "run time error? ", foo(x => 3, y => 7, $c => 5);

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?


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.

--abhijit

Larry Wall

unread,
Mar 3, 2005, 1:45:32 AM3/3/05
to perl6-l...@perl.org
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(*@args) 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

Abhijit Mahabal

unread,
Mar 3, 2005, 10:25:30 AM3/3/05
to perl6-l...@perl.org
Another edge case: is it legal to have an optional Pair in the
signature? That is:
sub foo($x, Pair ?$y, +$z){...}

If yes, what does this parse as:
foo(10, z => 5);

If z => 5 is bound to $y, then $y is almost mandatory. ('almost' because
we can still say foo(10); ). (and then can we also say foo(10, z => 5, z
=> 6)? :) That at least has the feature that it can be used to write
bizarre code like C< sing :e:i:e:i:o > )

If it is bound to $z instead, how do we bind anything to $y
positionally? Might as well change that to +$y.

It seems to me that an optional Pair is a catastrophe waiting to happen,
and maybe it should just be illegal (or produce a warning at least)

Sorry if this has been gone over before...

--abhijit

Larry Wall

unread,
Mar 3, 2005, 11:31:44 AM3/3/05
to perl6-l...@perl.org
On Thu, Mar 03, 2005 at 10:25:30AM -0500, Abhijit Mahabal wrote:
: Another edge case: is it legal to have an optional Pair in the
: signature? That is:
: sub foo($x, Pair ?$y, +$z){...}
:
: If yes, what does this parse as:
: foo(10, z => 5);

It ends up equivalent to foo(10, y => (z => 5), z => undef);

: If z => 5 is bound to $y, then $y is almost mandatory. ('almost' because

: we can still say foo(10); ). (and then can we also say foo(10, z => 5, z
: => 6)? :) That at least has the feature that it can be used to write
: bizarre code like C< sing :e:i:e:i:o > )
:
: If it is bound to $z instead, how do we bind anything to $y
: positionally? Might as well change that to +$y.

Er, by not naming it "z" maybe? But the situation doesn't arise.
Named binding only takes over after positional binding gives up.
So there's really not much ambiguity--the first pair is always bound
to $y, regardless of its name, and once that pair is slurped into
the second argument, it's no longer available for named binding,
and $z stays unbound.

: It seems to me that an optional Pair is a catastrophe waiting to happen,

: and maybe it should just be illegal (or produce a warning at least)

One can say catastrophic things in English too, and a few of those
are illegal, while a larger subset gets you a warning from your
mother--but by and large we don't outlaw stupid utterances, because
sometimes collections of stupid utterances can be rather clever.
If my writings are ever published posthumously, they should probably
be called "A Collection of Stupid Utterances", or some such... :-)

: Sorry if this has been gone over before...

Nope, hasn't--unless you count publishing the binding semantics as
pseudocode in A6 that implies the positional parameters always take
precedence over named. But we haven't made it terribly clear. Thanks.

Larry

Reply all
Reply to author
Forward
0 new messages