Skip to content

Lazy vals annotated with @threadUnsafe ignore @transient annotation #23487

Open
@kyri-petrou

Description

@kyri-petrou

Compiler version

3.3.6, 3.7.1

Minimized code

Lazy vals annotated with @threadUnsafe do not honour the @transient annotation:

case class Bar() {
  @transient @threadUnsafe
  lazy val value: Long = System.nanoTime()
}

While examining the compiler output should suffice to identify the issue, here's also a reproducer of this behaviour:

//> using scala 3.7.1

import java.io.*
import scala.annotation.threadUnsafe

// Serialize any object to a byte array
def serialize[T <: Serializable](obj: T): Array[Byte] = {
  val byteArrayOutputStream = new ByteArrayOutputStream()
  val objectOutputStream    = new ObjectOutputStream(byteArrayOutputStream)

  try {
    objectOutputStream.writeObject(obj)
    byteArrayOutputStream.toByteArray
  } finally {
    objectOutputStream.close()
    byteArrayOutputStream.close()
  }
}

// Deserialize from a byte array back to an object
def deserialize[T](bytes: Array[Byte]): T = {
  val byteArrayInputStream = new ByteArrayInputStream(bytes)
  val objectInputStream    = new ObjectInputStream(byteArrayInputStream)

  try {
    objectInputStream.readObject().asInstanceOf[T]
  } finally {
    objectInputStream.close()
    byteArrayInputStream.close()
  }
}

case class Foo() {
  @transient
  lazy val value: Long = System.nanoTime()
}

case class Bar() {
  @transient @threadUnsafe
  lazy val value: Long = System.nanoTime()
}

@main def main() = {
  val foo1 = Foo()
  foo1.value // init lazy val
  val foo2 = deserialize[Foo](serialize(foo1))
  assert(foo1.value != foo2.value, "Foo#value is not transient")

  val bar1 = Bar()
  bar1.value // init lazy val
  val bar2 = deserialize[Bar](serialize(bar1))
  assert(bar1.value != bar2.value, "Bar#value is not transient")
}

Output

Exception in thread "main" java.lang.AssertionError: assertion failed: Bar#value is not transient
	at scala.runtime.Scala3RunTime$.assertFailed(Scala3RunTime.scala:8)
	at Foo$package$.main(Foo.scala:50)
	at main.main(Foo.scala:41)

Expectation

I expect that lazy vals annotated with both @threadUnsafe and @transient honour the annotation, or if that's not possible (for some reason) a compiler warning should be raised for illegal combination of annotations

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions