Raku 如何处理钻石问题(多重继承)?

Ele*_*fee 7 multiple-inheritance diamond-problem raku

所以说乐拥有多重继承已经不是什么秘密了,这让我想知道:“乐如何以合理的方式处理它?”

一些初步测试表明默认行为是从继承列表中的第一个类继承的,这很好,许多其他语言也是这样做的

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)
Run Code Online (Sandbox Code Playgroud)

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

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

在 Raku 中处理这种情况的机制是什么?

Eli*_*sen 12

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

所以你的问题的答案是:speak向 D 类添加一个方法,并speak让它从类中调用该方法C

class D {
    ...
    method speak { self.C::speak }
}
Run Code Online (Sandbox Code Playgroud)

对于带参数的方法,取Capture所有参数中的一个,并将其传递:

class D {
    ...
    method foo(|c) { self.C::foo(|c) }
}
Run Code Online (Sandbox Code Playgroud)

请注意,“c”|c只是一个标识符,它可以是任何标识符。但是,至少对于 Raku 核心开发人员来说,使用 是一种习惯,|c其中“c”代表“捕获”。

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

class D {
    ...
    BEGIN D.^add_method("speak",C.^find_method("speak"));
}
Run Code Online (Sandbox Code Playgroud)

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