3

我的问题是关于 Odersky 的第 3.5 课(不是作业!):

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

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

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

4

4 回答 4

11

这与为什么以下内容无法在 Java 中编译类似的问题:

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

但这会编译:

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

基本上编译器必须在某处停止。尤其是 Scala 编译器,它已经很慢了。一旦它识别true出总是通过条件,人们可能会问:what about: 1 == 12 * 21 == 42甚至x == 7where xis val

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

于 2012-10-02T18:59:44.243 回答
4

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

于 2012-10-02T19:01:42.333 回答
2

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

做这样的预测也会使打字规则的逻辑复杂化。如果 if 语句的类型是 Int 并且其中一个分支的类型不是 Int 的子类型,那肯定会与人们的期望相矛盾——即使该分支永远不会被执行。在某种程度上,就像类型检查器不会抱怨它知道不会执行的分支中的类型错误一样——没有人想要那样。

于 2012-10-02T19:04:45.020 回答
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
于 2012-10-02T19:47:33.513 回答