Eli*_*sen 10 perl6 mop meta-object-protocol raku
如果您创建一个类:
class Foo { }
Run Code Online (Sandbox Code Playgroud)
该类将继承其所有方法Any,然后Mu.
我想创建一个不从任何其他类继承的类:它应该包含一个FALLBACK方法,该方法应该捕获对该对象实例的所有方法调用.
我查看了MetaModel代码,但似乎没有一种简单的方法来实现这一目标.欢迎所有建议!
更新:我决定采用Jonathan Worthington所描述的拦截任何方法调用方式.这导致CPAN上有两个新的Perl 6模块:InterceptAllMethods和Object :: Trampoline.
这是可能的,尽管您可能会遇到需要进一步努力的实际问题.调用构造逻辑是评论中已经指出的一个很好的例子.除此之外,预计一切都会成功进行检查Mu; 在大多数地方,这样的检查被省略为优化,而不是其他检查,因此您可能会遇到各种类型的检查失败.
除此之外,这是如何做到这一点.首先,创建一个为其导出新元类型的模块class.
class RootHOW is Metamodel::ClassHOW {
method has_default_parent_type(|) { False }
}
package EXPORTHOW {
constant class = RootHOW;
}
Run Code Online (Sandbox Code Playgroud)
元模型以某种方式被用来建立Mu在首位的类型,所以在这里我们(AB)使用了一种机制,通常是指"没有,没有默认父类型但因为我们没有引导我们的对象模型,远".将其粘贴到一个模块中,比如说Parentless,然后可以这样做:
use Parentless;
class NotAMu {
method FALLBACK($name, |c) {
say "called $name with {c.perl}"
}
}
NotAMu.new
Run Code Online (Sandbox Code Playgroud)
哪个输出:
called new with \()
Run Code Online (Sandbox Code Playgroud)
如果您的目标只是拦截每个方法调度,那么就不会破坏类型系统的破坏性方法.目前它需要一个禁用方法缓存发布的自定义元类:
class InterceptHOW is Metamodel::ClassHOW {
method publish_method_cache(|) { }
}
package EXPORTHOW {
constant class = InterceptHOW;
}
Run Code Online (Sandbox Code Playgroud)
然后你可以写:
use InterceptAllTheMethods;
class InterceptThemAll {
method ^find_method(Mu $obj, Str $name) {
return -> | { say "calling $name" }
}
}
InterceptThemAll.new
Run Code Online (Sandbox Code Playgroud)
请注意,与FALLBACK此不同的是,您将返回一个将被调用的代码对象.你也可以find_method在元类中编写这个实现,这可能是一个更好的因子; 在不知道手头的问题的情况下很难说.
这种方法不会导致与类型检查相关的问题,让您拦截每个方法调度,并且很容易查找类似的东西bless,并将它们委托给Mu实现.
这是另一个想法:您可以创建一个继承自的新元类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
}
Run Code Online (Sandbox Code Playgroud)
会成为
method can($obj, $name) {
my @meths;
my %smt := self.submethod_table($obj);
if nqp::existskey(%smt, $name) {
@meths.push(%smt{$name});
}
@meths
}
Run Code Online (Sandbox Code Playgroud)
这样你就不会遇到期望所有类型都符合的代码的麻烦Mu,但你仍然可以避免意外调用方法Mu.
| 归档时间: |
|
| 查看次数: |
220 次 |
| 最近记录: |