Back to Scala3

E009: Early Definitions Not Supported

docs/_docs/reference/error-codes/E009.md

3.8.43.2 KB
Original Source

E009: Early Definitions Not Supported

This error is emitted when using early definitions (early initializers), which were a feature in Scala 2 but are no longer supported in Scala 3. Use trait parameters instead.

Earlier versions of Scala did not support trait parameters and "early definitions" (also known as "early initializers") were used as an alternative to initialize values before the superclass constructor runs.

In Scala 3, trait parameters provide a cleaner solution to this problem.


Example

scala
trait Logging:
  val logFile: String
  println(s"Logging to $logFile")

class App extends { val logFile = "app.log" } with Logging

Error

scala
-- Error: example.scala:5:18 ---------------------------------------------------
5 |class App extends { val logFile = "app.log" } with Logging
  |                  ^
  |                  `extends` must be followed by at least one parent
-- [E009] Syntax Error: example.scala:5:46 -------------------------------------
5 |class App extends { val logFile = "app.log" } with Logging
  |                                              ^^^^
  |         Early definitions are not supported; use trait parameters instead
  |-----------------------------------------------------------------------------
  | Explanation (enabled by `-explain`)
  |- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
  | Earlier versions of Scala did not support trait parameters and "early
  | definitions" (also known as "early initializers") were used as an alternative.
  |
  | Example of old syntax:
  |
  | trait Logging {
  |   val f: File
  |   f.open()
  |   onExit(f.close())
  |   def log(msg: String) = f.write(msg)
  | }
  |
  | class B extends Logging {
  |   val f = new File("log.data") // triggers a NullPointerException
  | }
  |
  | // early definition gets around the NullPointerException
  | class C extends {
  |   val f = new File("log.data")
  | } with Logging
  |
  | The above code can now be written as:
  |
  | trait Logging(f: File) {
  |   f.open()
  |   onExit(f.close())
  |   def log(msg: String) = f.write(msg)
  | }
  |
  | class C extends Logging(new File("log.data"))
   -----------------------------------------------------------------------------
-- Error: example.scala:5:51 ---------------------------------------------------
5 |class App extends { val logFile = "app.log" } with Logging
  |                                                   ^^^^^^^
  |                  end of toplevel definition expected but identifier found

Solution

scala
// Use trait parameters instead of early definitions
trait Logging(logFile: String):
  println(s"Logging to $logFile")

class App extends Logging("app.log")
scala
// Alternative: Use a lazy val to defer initialization
trait Logging:
  def logFile: String
  lazy val logger = s"Logging to $logFile"

class App extends Logging:
  val logFile = "app.log"
<!-- SOURCE-ONLY: Remove the notice below once this page has been manually updated. --> <aside class="warning"> This reference page was created with LLM assistance - the description of the error code may not be accurate or cover all possible scenarios. </aside>