Autrijus wrote:
> A difficulty arises because the expressions used as arguments > is not evaluated when arityMatch is done, and for good reason -- > they may do wildly different things depending on its context. > > When Pugs was only implementing FP6, I could affort to force > evaluation for each multisub candidate, and see if they yield > values that can match the signature. However, because now the > expressions may contain "say" statements, I can no longer do that. > > As a concrete (not neccessarily correct) example: > > multi sub foo ($x, Int $y) returns Num { ... } > multi sub foo ($x, *$a, *$b) returns Str { ... } > > sub baz { given want { if (rand > .5) { ... } else { ... } } } > > foo( bar(), baz() ); > > I fail to find a way to statically find out how many values (and what > type of values) baz() will return under "Int" and "List" contexts, > short of actually evaluating it twice. Hence, the return type of > foo() can't be analyzed in advance because I don't know which foo() > will be invoked.
A6 acknowledges this fundamental problem with multiple dispatch:
If Perl can't figure out the signature of a function at compile time (because, for instance, it's a method and not a function), then it may not be known which arguments are in scalar or list context at the time they are evaluated. This doesn't matter for Perl variables, because in Perl 6, they always return a reference in either scalar or list context. But if you call a function in such an indeterminate context, and the function doesn't have a return value declared that clarifies whether the function behaves differently in scalar or list context, then one of two things must happen. The function must either run in an indeterminate context, or the actual call to the function must be delayed until the context is known. It is not yet clear which of these approaches is the lesser evil. It may well depend on whether the function pays more attention to its dynamic context or to global values. A function with no side effects and no global or dynamic dependencies can be called whenever we like, but we're not here to enforce the functional paradigm. Interesting functions may pay attention to their context, and they may have side effects such as reading from an input stream in a particular order.
A variant of running in indeterminate context is to simply assume the function is running in list context. (That is, after all, what Perl 5 does on methods and on not-yet-declared subroutines.)
Personally, I think the only reasonable way of resolving this is to assume (as in the last paragraph above) that function calls in these kinds of indeterminate contexts are always in list context. The logic is very simple: "We can't resolve its context; it's in an argument list; ergo it's in list context."
But there should definitely also be a (removable) warning:
Call to baz() in indeterminate context at foo.pl line 42 (did you forget a <== ?)
Propagating indeterminate contexts or deferring subroutine calls complicates
both the semantics and the implementation far more than is necessary for the marginal benefits likely to be gained.
>>So I think your initial solution is actually the right one from the >>viewpoint of the Perl programmer. If we need to tweak something, >>it's perhaps to document the fact that *$x is required to match an argument, >>while [EMAIL PROTECTED] isn't required to match any arguments at all. So if you >>had >> >> multi sub quicksort ( ) { () } >> multi sub quicksort ( [EMAIL PROTECTED] ) { >> >>then when dispatching 0 arguments you actually have an ambiguity that >>either has to be illegal or solved by ordered matching.
Multiple dispatch ambiguities are always solved by calling the C<is default> variant, or by throwing an:
Ambiguous call to multiply dispatched quicksort() at foo.pl line 42
exception if no variant C<is default>.
> In pugs, currently it's ordered by local vs global, then by subtyping > distance of invocants, then finally by then finally by the order of > creation of CODE objects. That's just a working heuristics, though.
The dispatch resolution process is described in A12, under "Calling via Multiple Dispatch". It's close to what you describe above, except the "local vs global" distinction is a little more complex, and the final discrimination is via C<is default>, not via C<Code> object creation sequence.
Damian