如何创建不继承任何其他 class 的 class?
How to create a class that doesn't inherit from any other class?
如果创建 class:
class Foo { }
class 将从 Any
继承其所有方法,然后 Mu
.
我想创建一个不继承任何其他 class 的 class:它应该包含一个 FALLBACK
方法,该方法应该捕获 all 对该对象实例的方法调用。
我查看了 MetaModel
代码,但似乎没有实现此目标的简单方法。欢迎所有建议!
更新:我决定采用 Jonathan Worthington 描述的拦截任何方法调用方式。这导致在 CPAN 上产生了两个新的 Perl 6 模块:InterceptAllMethods and Object::Trampoline.
这是可能的,尽管您可能 运行 遇到需要进一步努力的实际问题。调用构造逻辑是评论中已经指出的一个很好的例子。除此之外,一切都有望成功地针对 Mu
进行类型检查;此类检查在大多数地方都作为优化而被省略,但其他地方则不然,因此您可以预期 运行 各种类型检查失败。
除此之外,下面是操作方法。首先,创建一个为 class
.
导出新元类型的模块
class RootHOW is Metamodel::ClassHOW {
method has_default_parent_type(|) { False }
}
package EXPORTHOW {
constant class = RootHOW;
}
首先必须以某种方式使用元模型来设置 Mu
类型,因此在这里我们(滥用)使用通常表示 "no, there's no default parent type yet because we didn't bootstrap our object model that far" 的机制。将其粘贴到一个模块中,比如称为 Parentless
,然后就可以这样做:
use Parentless;
class NotAMu {
method FALLBACK($name, |c) {
say "called $name with {c.perl}"
}
}
NotAMu.new
输出:
called new with \()
如果您的目标只是拦截 every 方法分派,则有一种破坏性较小且不会扰乱类型系统的方法。目前它需要一个禁用方法缓存发布的自定义元类:
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
不同的是,此处您 return 一个随后将被调用的代码对象。您也可以在元类中编写此 find_method
实现,这可能是更好的因式分解;不知道手头的问题很难说。
这种方法不会导致与类型检查相关的问题,让您拦截每个方法分派,并且很容易查找 bless
之类的东西并将它们委托给 Mu
实现。
这是另一个想法:您可以创建一个继承自 ClassHOW
的新元 class,但会覆盖角色 Perl6::Metamodel::MROBasedMethodDispatch
提供的方法,版本跳过所有父 classes.
例如,这个:
# 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
的方法。
如果创建 class:
class Foo { }
class 将从 Any
继承其所有方法,然后 Mu
.
我想创建一个不继承任何其他 class 的 class:它应该包含一个 FALLBACK
方法,该方法应该捕获 all 对该对象实例的方法调用。
我查看了 MetaModel
代码,但似乎没有实现此目标的简单方法。欢迎所有建议!
更新:我决定采用 Jonathan Worthington 描述的拦截任何方法调用方式。这导致在 CPAN 上产生了两个新的 Perl 6 模块:InterceptAllMethods and Object::Trampoline.
这是可能的,尽管您可能 运行 遇到需要进一步努力的实际问题。调用构造逻辑是评论中已经指出的一个很好的例子。除此之外,一切都有望成功地针对 Mu
进行类型检查;此类检查在大多数地方都作为优化而被省略,但其他地方则不然,因此您可以预期 运行 各种类型检查失败。
除此之外,下面是操作方法。首先,创建一个为 class
.
class RootHOW is Metamodel::ClassHOW {
method has_default_parent_type(|) { False }
}
package EXPORTHOW {
constant class = RootHOW;
}
首先必须以某种方式使用元模型来设置 Mu
类型,因此在这里我们(滥用)使用通常表示 "no, there's no default parent type yet because we didn't bootstrap our object model that far" 的机制。将其粘贴到一个模块中,比如称为 Parentless
,然后就可以这样做:
use Parentless;
class NotAMu {
method FALLBACK($name, |c) {
say "called $name with {c.perl}"
}
}
NotAMu.new
输出:
called new with \()
如果您的目标只是拦截 every 方法分派,则有一种破坏性较小且不会扰乱类型系统的方法。目前它需要一个禁用方法缓存发布的自定义元类:
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
不同的是,此处您 return 一个随后将被调用的代码对象。您也可以在元类中编写此 find_method
实现,这可能是更好的因式分解;不知道手头的问题很难说。
这种方法不会导致与类型检查相关的问题,让您拦截每个方法分派,并且很容易查找 bless
之类的东西并将它们委托给 Mu
实现。
这是另一个想法:您可以创建一个继承自 ClassHOW
的新元 class,但会覆盖角色 Perl6::Metamodel::MROBasedMethodDispatch
提供的方法,版本跳过所有父 classes.
例如,这个:
# 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
的方法。