强制/类型检查:手动重现Perl6标准

Vad*_*man 10 perl6

我有一个模块AttrX::Mooish,它实现了Moo/Moose框架的一些属性特性(lazynes,trigger等).我还希望模块对最终用户尽可能透明,这意味着支持私有和公共属性.它的工作原理是将属性的容器替换为a Proxy并将其值存储在外部存储器中.这也意味着Perl6所做的所有类型检查和强制现在都是我的责任.我的目标是尽可能模仿默认行为.即最终用户:

has MyClass @foo is mooish(...);

必须像没有应用特性一样工作.不幸的是,类型操作的主题在语言核心中是如此复杂和不统一,以至于我解决的问题越多,我后来遇到的问题就越多.例如:

my Str @a = <a b c>; my Str @b = [1,2,3]

Type check failed in assignment to @b; expected Str but got Int (1)

正如所料.

my Str @a; say @a.WHAT

(Array[Str])

当然.

my Array[Str] $a = ["a", "b", "c"];

Type check failed in assignment to $a; expected Array[Str] but got Array ($["a", "b", "c"])

好....

my Array[Str] $a = <a b c>;

Type check failed in assignment to $a; expected Array[Str] but got List ($("a", "b", "c"))

甚至没有强迫ListArray!

难怪我的特质代码中的最终类型检查线:

$coerced-value ~~ $attr.type

尽管在变量/属性赋值中使用相同的值/类型,但这里和那里都会失败.

我有一个问题,没有希望得到任何肯定的答案:是否有一个入口操作符使用的入口点,它执行所有强制/类型检查?理想情况下我会简单地说:

$value = coerce($value, $type); check-type($value, :type($attr.type), :name($attr.name))

我试图从语法中追查,但还没有足够的业余时间来完成这个.此外,它主要是nqp,我不知道,也无法真正理解.

但由于存在这样的切入点,我不太可能要求提供与该领域相关的任何建议.例如,#perl6上的SmokeMachine为我提供了使用.^parents方法获取参数化类型的基本类型的好主意.

到目前为止,最大的问题是:

  1. 要检查类型是否已参数化,我不能使用单个角色或类来匹配.到目前为止,我唯一的方法是找出是否有of方法并测试其输出.不幸的是,如果一个类提供了FALLBACK非常不清楚的错误消息(关于AUTOGEN的那个)就会产生.:no_fallback是可取的,但确定和子集类型有自己的find_method不支持命名参数,我最终得到另一个错误消息.
  2. 如果我的特征角色方法中的与类型相关的属性($!coerce-type)compose应用于Attribute对象(实际上是声明了属性),我会在运行时稍后将其找到.猜测它与构成时间有关的东西.但是想确定这里是否遗漏了什么.
  3. 有没有更好的方法来执行类型检查$value ~~ $type

cod*_*ons 2

[评论表明这个过时的问题本应在 2020 年结束,但它从未结束。这是一个非常简短的答案,以防有人遇到这个问题。]

在提出这个问题后的某个时间,提问者对 Raku 的强制机制进行了重大修改。请参阅关于新强制的报告。这种新的强制转换语法位于文档中

使用这种新样式,问题中的以下行:

my Array[Str] $a = ["a", "b", "c"];
say $a;
# OUTPUT: Type check failed in assignment to $a; 
#         expected Array[Str] but got Array ($["a", "b", "c"])
Run Code Online (Sandbox Code Playgroud)

变成

my Array[Str]() $a = ["a", "b", "c"];
say $a;
# OUTPUT: [a b c]
Run Code Online (Sandbox Code Playgroud)

(也就是说,Array[Str]()意味着“可以强制转换为字符串数组的东西”。这不同于Array[Str()](“可以强制转换为字符串的东西的数组”) 和Array[Str()]()(“可以强制转换为字符串的东西的数组”可以强制转换为字符串”)。)

同样,问题的以下部分现在有了答案:

赋值运算符是否使用单个入口点来执行所有强制/类型检查?理想情况下,我会简单地[定义如何将类型强制为我的类型]

使用新的强制协议,“单一入口点”是方法COERCE用户可以为其类型定义该方法,以教 Raku 如何强制转换为这些类型。