E009: 초기 정의 미지원
E009: 초기 정의 미지원 (Early Definitions Not Supported)
이 에러는 얼리 정의(early definitions, 일명 early initializers)를 사용할 때 발생해요. Scala 2에는 있던 기능이지만 Scala 3에서는 더 이상 지원하지 않아요. 대신 트레이트 파라미터(trait parameters)를 쓰세요.
본문
이전 버전의 Scala는 트레이트 파라미터를 지원하지 않아서, 슈퍼클래스 생성자가 실행되기 전에 값을 초기화하기 위한 대안으로 "얼리 정의"(일명 "초기 정의"/early initializers)를 사용했어요.
Scala 3에서는 트레이트 파라미터가 이 문제에 더 깔끔한 해법을 제공해요.
Example
trait Logging:
val logFile: String
println(s"Logging to $logFile")
class App extends { val logFile = "app.log" } with Logging
Error
-- 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
// Use trait parameters instead of early definitions
trait Logging(logFile: String):
println(s"Logging to $logFile")
class App extends Logging("app.log")
// 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"
더 알아보기
- 트레이트 파라미터에 대한 자세한 내용은 "Traits" 섹션을 참고하세요.
- 초기화 순서 이슈에는
lazy val도 유용한 대안이에요.