Raku 如何处理菱形问题(多重继承)?

How does Raku deal with the diamond problem (multiple inheritance)?

所以 Raku 具有多重继承已经不是什么秘密了,这让我想知道:"how does Raku deal with that in any reasonable manner?"

一些初步测试表明,默认行为是从继承列表中的 first class 继承的,没关系,许多其他语言也是这样做的

class A {
    has $.foo = 0;

    method speak {...}
}

class B is A {
    has $.foo = 1;

    method speak {
        say 'moo';
    }
}

class C is A {
    has $.foo = 2;

    method speak {
        say 'baa';
    }
}

class D is B is C {}

class E is C is B {}

say D.new.foo; # prints 1 (from B)
say E.new.foo; # prints 2 (from C)

但这让我想知道,如果我想让 D 使用 Cspeak 怎么办? 由于继承顺序,我默认得到 B。

我知道角色的存在是为了通过促进消除歧义机制来解决这个确切的问题,但假设我发现自己处于一种我没有角色可供我支配的情况(老板讨厌他们,继承了一个没有的库'有它们,选择你的借口)并且真的需要消除继承的 classes 的歧义。

Raku 的处理机制是什么?

通常,您需要在 class 中提供一个具有(潜在)歧义的决胜方法。幸运的是,您不必创建单独的方法,因为您可以在调用中调用特定版本的方法。

所以你的问题的答案是:将方法 speak 添加到 class D,然后调用 class C 中的 speak 方法:

class D {
    ...
    method speak { self.C::speak }
}

对于采用参数的方法,采用所有参数的 Capture,并将其传递给:

class D {
    ...
    method foo(|c) { self.C::foo(|c) }
}

注意|c中的"c"只是一个标识符,可以是任何标识符。但至少对于 Raku 核心开发人员来说,习惯上只使用 |c,"c" 代表 "capture"。

现在,这将导致一些开销,因为您将有一个额外的间接级别。如果这是一个性能问题,您可以进行一些元编程,将 D 中的 speak 方法别名为 C 中的 speak 方法:

class D {
    ...
    BEGIN D.^add_method("speak",C.^find_method("speak"));
}

这将在编译时由于 BEGIN,将一个 Method 对象添加到 D class 调用的 speak 中定义class Cspeak 方法。由于这是一个别名,您不必担心传递任何参数。