代码之家  ›  专栏  ›  技术社区  ›  Elizabeth Mattijsen

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

  •  9
  • Elizabeth Mattijsen  · 技术社区  · 8 年前

    如果创建类:

    class Foo { }
    

    类将继承其所有方法 Any ,然后 Mu 是的。

    我想创建一个不从任何其他类继承的类:它应该包含一个 FALLBACK 应该捕获的方法 全部的 方法调用该对象的实例。

    我已经看过了 MetaModel 代码,但似乎没有一个简单的方法来实现这个目标。欢迎所有建议!

    更新 :我决定去 拦截任何方法调用 就像乔纳森·沃辛顿描述的那样。这在cpan上产生了两个新的perl 6模块: InterceptAllMethods Object::Trampoline 是的。

    2 回复  |  直到 7 年前
        1
  •  9
  •   Jonathan Worthington    8 年前

    这是可能的,尽管你可能会遇到需要进一步努力的实际问题。调用构造逻辑是注释中已经指出的一个很好的例子。除此之外,所有内容都将成功地进行类型检查 Mu 在大多数地方,这种检查被认为是一种优化,而不是其他地方,因此您可以预期会遇到各种类型的检查失败。

    撇开这一点,我们来看看怎么做。首先,创建一个模块,该模块为 class 是的。

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

    元模型必须以某种方式被用来建立 首先输入,所以这里我们(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 把这些交给 实施。

        2
  •  6
  •   moritz    8 年前

    这里还有一个想法:您可以创建一个继承自 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 ,但仍然可以避免意外调用 是的。

    推荐文章