我在 Facebook 从事 Hack 类型系统和类型检查器的工作。这个问题已经在 FB 内部被问过几次,最好有一个很好的、外部可见的地方来写下这个问题的答案。
因此,首先,您的问题是以以下代码为前提的:
<?hh // strict
function main() : void {
$myVector = new Vector([]); // no generic syntax
$myVector->addAll(require 'some_external_source.php');
}
但是,由于使用了外部顶层,该代码没有通过类型检查器require
,因此在 HHVM 上实际执行它的任何结果都是未定义的行为,使得整个讨论对该代码没有意义。
但对于其他实际进行类型检查的潜在代码片段来说,这仍然是一个合理的问题,所以让我继续实际回答它。:)
不支持它的原因是因为类型检查器实际上能够正确地推断出泛型,这与许多其他语言不同,因此我们做出了语法会妨碍的判断调用,并决定禁止它。事实证明,如果您不担心,我们会正确推断,并且仍然会给出有用的类型错误。您当然可以想出不会以您想要的方式“快速失败”的人为代码,但是它是人为的。以您的示例的此修复为例:
<?hh // strict
function main(): void {
$myVector = Vector {}; // I intend this to be a Vector<int>
$myVector[] = 0;
$myVector[] = 'oops'; // Oops! Now it's inferred to be a Vector<mixed>
}
您可能会争辩说这很糟糕,因为您打算有一个Vector<int>
但实际上有一个Vector<mixed>
没有类型错误;您希望能够在创建它时表达这一点,以便添加'oops'
到它会导致这样的错误。但是没有类型错误只是因为您从未真正尝试过使用$myVector
!如果你试图取出它的任何值,或者从函数中返回它,你会得到某种类型的兼容性错误。例如:
<?hh // strict
function main(): Vector<int> {
$myVector = Vector {}; // I intend this to be a Vector<int>
$myVector[] = 0;
$myVector[] = 'oops'; // Oops! Now it's inferred to be a Vector<mixed>
return $myVector; // Type error!
}
该return
语句将导致类型错误,说'oops'
是一个字符串,与int
返回类型注释不兼容——正是你想要的。所以推理很好,它有效,而且你实际上不需要显式地注释本地人的类型。
但是,如果您真的想要,为什么不可以呢?因为在实例化新对象时仅注释泛型并不是真正的正确功能。你所说的“但偶尔我真的想注释Vector<int> {}
”的核心实际上是“但偶尔我真的想注释本地人”。所以正确的语言特性不是让你写$x = Vector<int> {};
,而是让你显式声明变量并写Vector<int> $x = Vector {};
——这也允许像int $x = 42;
. 向语言中添加显式变量声明是一种更通用、更合理的添加,而不仅仅是在对象实例化时注释泛型。(然而,这不是一个正在积极开发的功能,我也看不到它在近期到中期的未来是这样的,所以现在不要抱太大希望。但是让选项保持开放是我们做出这个决定的原因。)
此外,此时允许使用其中任何一种语法都会产生误导。泛型仅由静态类型检查器强制执行,并由运行时擦除。这意味着如果您从 PHP 或 Hack 部分模式代码中获取无类型值,则运行时可能无法检查泛型的真实类型。请注意,无类型值是“信任程序员”,因此您也可以在静态类型检查器中对它们执行任何操作,请考虑以下代码,其中包括您建议的假设语法:
<?hh // partial
function get_foo() /* unannotated */ {
return 'not an int';
}
<?hh // strict
function f(): void {
$v = Vector<int> {};
$v[] = 1; // OK
// $v[] = 'whoops'; // Error since explicitly annotated as Vector<int>
// No error from static typechecker since get_foo is unannotated
// No error from runtime since generics are erased
$v[] = get_foo();
}
当然,你不能在 100% 严格模式代码中拥有未注释的值,但我们必须考虑它如何与所有潜在用途交互,包括部分模式甚至 PHP 中的无类型代码。