Hi all,
I would like to trigger a discussion about the planned removal of DelayedInit
in Scala 3.
specs2
has been using DelayedInit
almost since its inception as a way to create a Scope
for a given test:
class ContextSpec extends mutable.Specification {
"this is the first example" in new directories {
directory1.files must beEmpty
directory2.files must not(beEmpty)
}
}
trait directories extends Scope {
val directory1 = createEmptyDirectory
val directory2 = createDirectoryWithFiles("f1.txt", "f2.txt")
}
This allows users to define a bunch of variables (directory1
, directory2
, which are initialized first then accessed from the body of a trait. The alternative using Scala 3 would be to use specs2 ForEach
:
class ContextSpec extends mutable.Specification with FileSystem {
"this is the first example" in { directories: Directories =>
import directories._
directory1.files must beEmpty
directory2.files must not(beEmpty)
}
}
case class Directories(directory1: Directory, directory2: Directory)
trait FileSystem extends ForEach[Directories] {
def foreach[R: AsResult](f: Directories => R): Result =
f(createDirectories)
}
This other version is a bit more verbose but my main concern is all the code that is out there using Scope
and DelayedInit
under the covers. Also it could be argued that it is in general useful to intercept the execution of code in the body of a class. This enables better error messages when a class is instantiated through reflection if it throws an exception. We can then intercept that exception and report a better error message than NoClassDefFoundError
, maybe something like “you should probably use lazy vals :-)”.