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

Reply via email to