Here's a good Perl 6 final exam question:

Spot the mistake (hint: it's not in the math):

    module Complex;

    sub i() is export { 
        Complex.new(0,1)
    }
    multi sub infix:<+> (Complex $left, Complex $right) is export {
        Complex.new($left.real + $right.real, $left.imag + $right.imag);
    }
    multi sub infix:<*> (Complex $left, Complex $right) is export {
        Complex.new(
            $left.real * $right.real - $left.imag * $right.imag,
            $left.real * $right.imag + $right.real * $left.imag)
    }
    # ...

Give up?

When you add two complex numbers, you get into an infinite loop. 
That's because infix:<+> adds things using the plus operator, which
is, you guessed it, infix:<+>.  Now you'd think that multimethods
would handle that, but they don't because by defining "multi sub
infix:<+>" you are defining a *package* operator which *masks* the
global operator!  So this turns into infinite recursion.

By the way, this was done in Set.pm.  Pugs's scoping rules were
recently fixed, so suddenly the subtraction operator became an
infinite loop.

I see two solutions:

    1) Disallow a "multi" to introduce a symbol if it masks another
symbol of the same name.  You must explicitly ask for masking by
predeclaring the symbol without "multi" somewhere before you define
the multi.  This still doesn't solve anything when you accidentally
put "is export" on an operator (as was done in Set.pm).
    2) Make multi automatically find the symbol that you would have
referred to if the definition had not been there, and add a multi case
to that symbol.  So in the example above, the innermost infix:<+> that
existed before you said "multi" was *infix:<+>, so the multi
definition would basically infer that you meant to say multi
*infix:<+> and do the right thing.

There could also be some combination of the two.  Maybe something else
entirely.  Ideas?

Luke

Reply via email to