是的,我相信这已经是我们讨论了很久的事情,并且以某种形式实现了。
关键问题是编译器实际上不知道表达式的类型,它只知道正在报告的类型,而且这可能来自提示类型流,这可能与后来的运行时现实不符。
一个具体的例子
(defn remove [^Collection coll ^Predicate pred]
(.removeIf coll pred)))
在这里,removeIf的调用需要一个Predicate,并且pred局部变量将会有一个Predicate类型。但Clojure将提示视为提示,而不是静态类型签名,你可以传递实际的Predicate或IFn。在发出代码中的类型检查允许两者透明地工作。
更微妙的是,你可能甚至只对pred参数提供了类型提示: (.removeIf coll ^Predicate pred)
以解决重载(在本例中不是这样,但有一些是这样的),即使你知道pred不是一个Predicate而FI适配正是你想要的。一种可能的解决方案是使用新的参数标签元数据来指示首选的重载 (^[_ Predicate] Collection/.removeIf coll pred)
但这需要非常懂行才容易理解和应用。
我们也研究了调用和let绑定情况的不同行为,也许可以对let这样做,但不适用于调用。最终,唯一的安全做法是在运行时进行检查。
接下来的问题是这个检查的成本,通常在我的性能测试中,我找不到可检测的性能成本 - 你通常是在将函数传递给其他某处,那才是真正的成本驱动因素(将Predicate传递给.filter或Function传递给.map等等)。特别是在较新的JVM和CPU上,如果你恰好在循环中,所有的操作都会得到优化和正确预测。