Odersky的Coursera讲座:为什么类型检查器不能推断值类型Int?

时间:2012-10-02 18:53:04

标签: scala type-inference

我的问题是关于奥德斯基的讲座3.5(不是作业!):

19:15的练习问:“if (true) 1 else false”是什么类型的

在他的解释中,Odersky认为类型是AnyVal,因为它是IntBoolean(两个条件分支的类型)中最具体的超类型。

我问自己为什么类型检查器不够聪明,只能看到第一个分支实际上是相关的,因此可以将类型推断为Int

4 个答案:

答案 0 :(得分:11)

这是一个类似的问题,为什么以下不能用Java编译:

throw new Foo();
return 42;  //unreachable statement

但这会编译:

if(true)
  throw new Foo();
return 42;

基本上编译器必须停在某处。特别是Scala编译器,已经很慢了。一旦它将true视为始终通过条件,您可能会问:1 == 12 * 21 == 42甚至是x == 7,其中xval

很难绘制一条线,因此编译器只是假设每个if都可以有两个分支。 IDE或代码验证工具负责发现这些不可能或可能不正确的表达。

答案 1 :(得分:4)

我认为你不希望Int - 推断的类型不应该依赖于优化,而应该依赖于开发人员编写的文本。否则,很难预测你会得到什么 - 被授予,而不是在这种情况下,但它显然比大多数人更明显。

答案 2 :(得分:2)

因为类型检查器不对程序的执行做出任何假设。它不会尝试预测if语句的哪个分支将执行。在一般情况下,这是不可判定的,而且这种特殊情况在实践中不会经常发生,使任何此类预测都值得。

执行此类预测还会使输入规则的逻辑变得复杂。如果if语句的类型是Int,而其中一个分支的类型不是Int的子类型,那肯定会与人们的期望相矛盾 - 即使分支永远不会被执行。在某种程度上,就像类型检查器不会抱怨它知道不会执行的分支中的类型错误一样 - 没有人会想要它。

答案 3 :(得分:0)

这让我思考,因为你可以移动到定义true的地方。在某些时候,编译器需要遵循很多路径来提出它的最佳猜测。

这总是如此

if (true) 1 else false

也是如此,但处于更高的水平

val presetBoolean = true
if (presetBoolean) 1 else false

这样,但是通过评估表达式

val presetBoolean = (1 == 1)
if (presetBoolean) 1 else false

这也是常量,但在这种情况下,它将引用传递给另一个对象(并且是我程序中唯一的实例

case object CallWithPreset {
  def apply(presetBoolean:Boolean) {
    if(presetBoolean) 1 else false
  }
}

CallWithPreset(true)

每个推理都有编译时间形式的开销。因此,虽然我认为在琐碎的情况下它可能很容易,但在其他情况下可能不会。但是,如果您允许某些情况而不是所有情况,则会导致每个情况可能具有不同的推断并且可能会造成混淆。

例如,如果有效:

val myType:Int = if(true) 1 else false

但这给出了编译错误:

val presetBoolean = true
val myType:Int = if (presetBoolean) 1 else false