值类、普适性与实例化的必要性

Value classes, universal traits and the necessity of instantiation

specification of value classes 中,它说:

A value class can only extend universal traits and cannot be extended itself. A universal trait is a trait that extends Any, only has defs as members, and does no initialization. Universal traits allow basic inheritance of methods for value classes, but they incur the overhead of allocation. For example

trait Printable extends Any {
  def print(): Unit = println(this)
}
class Wrapper(val underlying: Int) extends AnyVal with Printable

val w = new Wrapper(3)
w.print() // actually requires instantiating a Wrapper instance

第一个问题

现在,我认为这意味着以下(可能)不需要实例化:

trait Marker extends Any
class Wrapper(val underlying: Int) extends AnyVal with Marker {
  def print(): Unit = println(this) //unrelated to Marker
}

val w = new Wrapper(3)
w.print() //probably no instantiation as print is unrelated to Marker

我说得对吗?

第二个问题

而且我认为关于这是否需要实例化的机会均等:

trait Printable extends Any {
  def print(): Unit //no implementation
}
class Wrapper(val underlying: Int) extends AnyVal with Printable {
  override def print() = println(this) //moved impl to value class
}

val w = new Wrapper(3)
w.print() // possibly requires instantiation

在概率的平衡上,我也认为不需要实例化 - 我是对的吗?

编辑

我没有考虑示例中 print() 的确切实现:

def print(): Unit = println(this)

假设我改用了以下内容:

def print(): Unit = println(underlying)

这些会导致实例化吗?

Am I correct?

不,如果我们使用 -Xprint:jvm:

发出最终编译输出,我们就可以看到它
<synthetic> object F$Wrapper extends Object {
  final def print$extension($this: Int): Unit = 
    scala.Predef.println(new com.testing.F$Wrapper($this));

这是因为 println 的类型签名需要 Any,所以我们在这里搬起石头砸自己的脚,因为我们实际上是 "treating the value class ttpe as another type"。

虽然调用被分派到静态方法调用:

val w: Int = 3;
F$Wrapper.print$extension(w)

我们仍在 print$extension 内进行分配。


如果我们偏离使用 Wrapper.this,那么您的第一个假设确实是正确的,我们可以看到编译器愉快地展开 Wrapper:

<synthetic> object F$Wrapper extends Object {
  final def print$extension($this: Int): Unit = 
    scala.Predef.println(scala.Int.box($this));

现在调用站点如下所示:

val w: Int = 3;
com.testing.F$Wrapper.print$extension(w)

现在这对您的两个示例都有效,因为创建的界面上不需要任何动态调度。