You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
The following example illustrates how classes in a subclass relation
11
+
witness the initialization of two fields which are inherited from
12
+
their top-most parent. The values are printed during the constructor
13
+
of each class, that is, when an instance is initialized.
11
14
12
15
abstract class A {
13
16
val x1: String
14
17
val x2: String = "mom"
15
18
16
-
println("A: " + x1 + ", " + x2)
19
+
println(s"A: $x1, $x2")
17
20
}
18
21
class B extends A {
19
22
val x1: String = "hello"
20
23
21
-
println("B: " + x1 + ", " + x2)
24
+
println(s"B: $x1, $x2")
22
25
}
23
26
class C extends B {
24
27
override val x2: String = "dad"
25
28
26
-
println("C: " + x1 + ", " + x2)
29
+
println(s"C: $x1, $x2")
27
30
}
28
31
29
32
In the Scala REPL we observe:
@@ -33,39 +36,46 @@ In the Scala REPL we observe:
33
36
B: hello, null
34
37
C: hello, dad
35
38
36
-
Only when we get to the constructor of `C` are both `x1` and `x2` initialized. Therefore, constructors of `A` and `B` risk running into `NullPointerException`s.
39
+
Only when we get to the constructor of `C` are both `x1` and `x2` properly initialized.
40
+
Therefore, constructors of `A` and `B` risk running into `NullPointerException`s,
41
+
since fields are null-valued until set by a constructor.
37
42
38
43
## Explanation
39
44
40
-
A "strict" or "eager" val is one which is not marked lazy.
45
+
A "strict" or "eager" val is a `val`which is not a `lazy val`.
41
46
Initialization of strict vals is done in the following order:
42
47
43
48
1. Superclasses are fully initialized before subclasses.
44
-
2. Otherwise, in declaration order.
49
+
2. Within the body or "template" of a class, vals are initialized in declaration order,
50
+
the order in which they are written in source.
45
51
46
-
When a `val` is overridden, in fact its accessor method (the "getter") is overridden.
47
-
So the access to `x2` in class `A` in fact invokes the overridden getter in class `C` which reads the underlying field `C.x2`.
52
+
When a `val` is overridden, it's more precise to say that its accessor method (the "getter") is overridden.
53
+
So the access to `x2` in class `A` invokes the overridden getter in class `C`.
54
+
That getter reads the underlying field `C.x2`.
48
55
This field is not yet initialized during the construction of `A`.
49
56
50
57
## Mitigation
51
58
52
-
The [`-Ysafe-init` compiler flag](https://docs.scala-lang.org/scala3/reference/other-new-features/safe-initialization.html) in Scala 3 enables compiler warnings for accesses to uninitialized fields:
59
+
The [`-Wsafe-init` compiler flag](https://docs.scala-lang.org/scala3/reference/other-new-features/safe-initialization.html)
60
+
in Scala 3 enables a compile-time warning for accesses to uninitialized fields:
0 commit comments