【发布时间】:2014-09-12 06:14:24
【问题描述】:
上下文
我们正在为 Scala 程序开发静态验证器(this Master's thesis 中描述的早期工作),当前的重点在于验证涉及惰性求值的 Scala 功能。我们主要对特征的语义(行为)感兴趣,而不是其他(尽管如此重要)方面,例如可理解性或简洁性。
为了简化事情,我们暂时忽略了单例对象可能具有的特殊角色。例如,有些是伴生对象(这可能与它们的惰性性质正交),或者有些是包对象。
惰性 val 和单例对象的属性
延迟验证
假设一个惰性值
lazy val v = I
I 是 initialiser 块,即确定惰性值的值的代码。初始化程序块 I 在第一次取消引用惰性 val v 时执行。
单例对象
假设一个单例对象
object Foo {
C1
val v1 = I1
var v2 = I2
lazy val v3 = I3
def m() {C2}
}
其中C1 是构成对象Foo 的构造函数的代码,其中I1 到I3 又是初始化块,其中C2 是方法m 的主体。当对象Foo第一次被使用(取消引用,或分配给一个变量/字段),然后C1, I1和I2被执行。 I3 仅在取消引用 Foo.v3 时执行(因为 v3 是一个惰性 val)并且每当调用 m 时都会执行 C2。
问题
考虑Foo 的这个版本,其中单例对象已由惰性 val 和匿名类编码:
// Should probably sit in a package object
lazy val Foo = new {
C1
val v1 = I1
var v2 = I2
lazy val v3 = I3
def m() {C2}
}
谁能想到为什么将单例对象 Foo 编码为惰性 val 会显示出与原始单例对象不同的行为的原因?也就是说,是否存在(角落)编码版本与原始代码具有不同语义的情况?
【问题讨论】:
-
这是一个很好的问题——例如,参见 this answer 和 Miles Sabin 的评论,其中一个例子是 存在差异(不确定 应该是,不过)。
-
感谢指点!不过,我对 Miles 评论的解释是,如果对象被编码为惰性 val,
Poly1的实现将无法编译,原因主要是由于名称解析。这与我想的不太一样,因为被编译器拒绝的代码显然表现出不同的行为。此外,如果问题真的“只是”由于名称解析,那么应该可以以不影响语言语义的方式解决它。但当然这只是我的猜测......
标签: scala singleton semantics lazy-evaluation