它使类型检查变得复杂。
当您仅允许基于参数类型的重载,并且仅允许从其初始化程序推导变量类型时,所有类型信息都朝一个方向流动:在语法树上。
var x = f();
given f : () -> int [upward]
given () : () [upward]
therefore f() : int [upward]
therefore x : int [upward]
当您允许类型信息在两个方向上传播时(例如,根据变量的用法推导变量的类型),您需要一个约束求解器(例如Hindley-Milner类型系统的Algorithm W)来确定类型。
var x = parse("123");
print_int(x);
given parse : string -> T [upward]
given "123" : string [upward]
therefore parse("123") : ∃T [upward]
therefore x : ∃T [upward]
given print_int : int -> () [upward]
therefore print_int(x) : () [upward]
therefore int -> () = ∃T -> () [downward]
therefore ∃T = int [downward]
therefore x : int [downward]
在这里,我们需要将type x
作为未解析的type变量保留,我们所∃T
知道的仅是可解析的。直到以后,当x
将其用于具体类型时,我们才具有足够的信息来解决约束并确定约束∃T = int
,从而将类型信息从调用表达式向下传播到语法树中x
。
如果我们无法确定的类型x
,那么该代码也将被重载(以便调用者确定类型),或者我们将不得不报告有关歧义的错误。
由此,语言设计师可以得出以下结论:
它增加了实现的复杂性。
在病理情况下,它会使类型检查变慢,呈指数级下降。
很难产生良好的错误消息。
它与现状有很大的不同。
我不想实现它。
Foo
和)时,您的问题可能会更好Bar
。