这个答案旨在补充@donaldh的答案,尽管我也不知道任何针对Perl 6类型/类型约束的特定研究。
静态类型检查很快
在下面的代码中,编译器会在编译时进行Complex~~Real
类型检查:
sub mySub(Real $probability where 0 < * < 1) {
# Do stuff with $probability
}
my Complex \number = 1-2e3i;
mySub number;
编译上述代码时,Rakudo编译器意识到
number
是
Complex
——因此您会得到一个
编译时类型检查失败的错误提示:
===SORRY!=== Error while compiling
Calling mySub(Complex) will never work with declared signature (Real $probability)
随着时间推移,像Rakudo这样的Perl 6编译器可以改善它们的编译时代码分析,从而在编译时进行更多类型检查,如上所述。
请注意,甚至没有尝试使用“where”子句。仅仅指定“where”子句没有任何惩罚。由于“where”子句导致的任何开销只有在变量/值通过基本类型检查后才适用。
大多数动态类型检查也很快
在下面的示例中,编译器在运行时执行了Complex~~Real类型检查:
multi sub mySub(Real $probability where 0 < * < 1) {
}
multi sub mySub(Complex $probability) {
}
my \number = 1-2e3i;
mySub number;
编译上述代码时,Rakudo编译器目前不会在编译时意识到
number
是
Complex
。在运行时,它考虑并拒绝第一个
multi sub
声明。与之前相同,它甚至不尝试使用
where
子句。相反,它成功调用了第二个
multi sub
。
迄今为止的例子应该清楚地表明,对于大多数类型检查来说,要么根本不需要,要么几乎没有运行时性能损失。
原生类型
理论上,可以使用原生类型以获得更好的性能:
sub foo-Int (Int $a) { my Int $b; $b++ for ^$a }
sub foo-int (int $a) { my int $b; $b++ for ^$a }
my $time;
$time = now; foo-Int my Int $ = 1e6.Int; say now - $time;
$time = now; foo-int my int $ = 1e6.Int; say now - $time;
在实践中,指定本地类型有时会减慢代码速度。
随着Rakudo的优化改进,相对于Int,int优化应变得更加一致和重要。其他本地标量类型和本地数组也适用类似的情况。
强制类型转换
Perl 6支持“强制类型转换”。
例如,Str(Int)接受任何Int或其子类型,并将其强制转换为Str。
如果强制类型转换的内部类型匹配,则编译器还将承担运行时开销来运行强制类型转换代码。
where子句
在完成上述常规静态和动态类型检查后,调用任何适用的where子句,直到其中一个成功或所有都失败。
编译器可以分析
where
子句并意识到它们等效于足够简单的静态类型表达式(例如
where Int | Str
),并使用此信息避免运行任意代码所带来的运行时开销。(参见
@Larry's speculation about related matters。)目前的Rakudo不分析
where
子句。实际上,它比严格需要更频繁地调用
where
子句。
编译器/后端的性能是特定编译器/后端的函数。
截至2017年,主要的Perl 6编译器是Rakudo/MoarVM。过去曾有其他编译器编译了Perl 6的重要子集,
未来也肯定会有;这些可能提供额外的数据。
“可选类型”与“渐进类型”
Perl 6引入了可选类型
如果您决定在网络上搜索相关数据...
Perl 6支持类继承和多分派等功能。根据维基百科的
定义,这两个功能都在技术上使Perl 6无法拥有“可选类型”系统。
维基百科将Perl 6放在
“渐进式类型”的广泛类别中,Larry Wall和doc.perl6.org也是如此。