7

我首先问过这个关于final在 Java 中使用 with 匿名内部类的问题: 为什么我们在匿名内部类中使用 final 关键字?

我实际上正在阅读 Martin Odersky 的 Scala 书。看起来 Scala 简化了很多 Java 代码,但是对于 Scala 闭包,我可以注意到一个显着的不同。

虽然在 Java 中我们使用匿名内部类“模拟”闭包,捕获一个最终变量(它将被复制到堆而不是堆栈上),但在 Scala 中我们似乎可以创建一个可以捕获 val 的闭包,但是也是一个 var,因此在闭包调用中更新它!

所以就像我们可以在没有final关键字的情况下使用 Java 匿名内部类!我还没有读完这本书,但目前我还没有找到关于这种语言设计选择的足够信息。

有人能告诉我为什么 Martin Odersky,他似乎真的很关心函数的副作用,选择闭包来同时捕获valandvar而不是只捕获val

Java 和 Scala 实现的优缺点是什么?

谢谢

相关问题: 使用 Scala 闭包,捕获的变量何时开始存在于 JVM 堆上?

4

2 回答 2

8

一个对象可以看作是一袋闭包,它们共享对同一环境的访问,并且该环境通常是可变的。那么为什么要让匿名函数生成的闭包不那么强大呢?

此外,其他具有可变变量和匿名函数的语言也以相同的方式工作。租赁惊奇原则。Java 实际上很奇怪,它不允许内部类捕获可变变量。

有时它们只是非常有用。例如,一个自我修改的 thunk 以创建您自己的惰性或未来处理变体。

缺点?它们具有共享可变状态的所有缺点。

于 2012-10-11T04:46:12.250 回答
1

以下是一些优点和缺点。

语言设计中有一条原则,即程序员应该清楚某物的成本。(我在 Holt 的《图灵语言的设计和定义》中第一次看到这一点,但我忘记了他给它起的名字。)两个看起来一样的东西应该是一样的。两个本地变量应该有相似的成本。这对 Java 有利。Java 中的两个本地变量的实现方式相同,因此无论内部类中是否提及其中一个变量,它们的成本都相同。Java 的另一优点是,在大多数情况下,捕获的变量确实是最终的,因此阻止程序员捕获非最终本地变量的成本很小。对 final 的坚持也简化了编译器,因为这意味着所有局部变量都是堆栈变量。

语言设计的另一个原则是正交的。如果可以捕获 val 为什么不能捕获 var。只要有合理的解释,何必设限制。当语言不够正交时,它们似乎是不正当的。另一方面,具有太多正交性的语言可能具有复杂的(因此有错误和/或延迟和/或很少)实现。例如,Algol 68 在黑桃上具有正交性,但实施起来并不容易,这意味着实施很少,吸收也很少。Pascal(大约在同一时间设计)有各种不雅的限制,使编写编译器更容易。结果是大量的实施和大量的吸收。

于 2012-10-11T03:04:44.130 回答