如何创建不继承自其他任何类的类?

时间:2018-06-25 20:19:04

标签: perl6 raku mop meta-object-protocol

如果您创建课程:

class Foo { }

该类将从Any,然后从Mu继承其所有方法。

我想创建一个不继承自其他任何类的类:它应包含一个FALLBACK方法,该方法应捕获对该对象实例的 all 方法调用。 / p>

我已经浏览了MetaModel代码,但是似乎没有一种简单的方法可以实现此目标。欢迎所有建议!

更新:我决定采用Jonathan Worthington所述的拦截任何方法调用的方式。这样就在CPAN上产生了两个新的Perl 6模块:InterceptAllMethodsObject::Trampoline

2 个答案:

答案 0 :(得分:9)

这是可能的,尽管您可能会遇到需要进一步努力的实际问题。调用构造逻辑是注释中已经指出的一个很好的例子。除此之外,一切都有望成功针对Mu进行类型检查;此类检查在大多数地方都作为优化而被省略,而其他地方则没有,因此,您可能会遇到各种类型的检查失败。

此外,这是操作方法。首先,创建一个模块,为class导出新的元类型。

class RootHOW is Metamodel::ClassHOW {
    method has_default_parent_type(|) { False }
}
package EXPORTHOW {
    constant class = RootHOW;
}

首先必须使用元模型来设置Mu类型,因此这里(ab)使用一种机制,通常意味着“不,还没有默认的父类型,因为我们没有不会引导我们的对象模型那么远”。将其粘贴到一个名为Parentless的模块中,然后可以执行以下操作:

use Parentless;
class NotAMu {
    method FALLBACK($name, |c) {
        say "called $name with {c.perl}"
    }
}
NotAMu.new

哪个输出:

called new with \()

如果您的目标只是截取每一个方法的派发,那么有一种破坏性较小的方式,不会与类型系统混淆。目前,它需要一个自定义元类来禁用方法缓存的发布:

class InterceptHOW is Metamodel::ClassHOW {
    method publish_method_cache(|) { }
}
package EXPORTHOW {
    constant class = InterceptHOW;
}

然后您可以编写:

use InterceptAllTheMethods;
class InterceptThemAll {
    method ^find_method(Mu $obj, Str $name) {
        return -> | { say "calling $name" }
    }
}
InterceptThemAll.new

请注意,与FALLBACK不同的是,您在此处返回一个将随后被调用的代码对象。您也可以在元类中编写此find_method实现,这可能是一个更好的选择。不知道眼前的问题很难说。

这种方法不会引起类型检查相关的问题,让您拦截每个方法的分派,并且很容易查找诸如bless之类的东西并将它们委托给Mu实现。

答案 1 :(得分:6)

这是另一个想法:您可以创建一个继承自ClassHOW的新元类,但是可以覆盖角色Perl6::Metamodel::MROBasedMethodDispatch提供的方法(该方法可以跳过所有父类)。

例如,此:

# Maybe this belongs on a role. Also, may be worth memoizing.
method can($obj, $name) {
    my @meths;
    my %smt := self.submethod_table($obj);
    if nqp::existskey(%smt, $name) {
        @meths.push(%smt{$name});
    }
    for self.mro($obj) {
        my %mt := $_.HOW.method_table($_);
        if nqp::existskey(%mt, $name) {
            @meths.push(%mt{$name})
        }
    }
    @meths
}

将成为

method can($obj, $name) {
    my @meths;
    my %smt := self.submethod_table($obj);
    if nqp::existskey(%smt, $name) {
        @meths.push(%smt{$name});
    }
    @meths
}

这样,您就不会遇到期望所有类型都符合Mu的代码的麻烦,但是您仍然可以避免意外地从Mu调用方法。