I have the below Scala code, where I want to use a superclass' require
clause from a case object where the parameters used in require
are overwritten:
sealed abstract class C(val i: Int) {
protected val min: Int = 1
protected val max: Int = 5
require(i >= min && i <= max,
s"$i should be between $min and $max, inclusive")
}
case object O extends C(3) {
override protected val min: Int = 3
override protected val max: Int = 5
}
println(O)
However, printing O
gives me java.lang.IllegalArgumentException: requirement failed: 3 should be between 0 and 0, inclusive
exception.
Overwriting only one of the parameters:
case object O extends C(3) {
override protected val max: Int = 5
}
Results in the exception java.lang.IllegalArgumentException: requirement failed: 3 should be between 1 and 0, inclusive
.
To me, this suggests that the superclass' require
is called before the overriding of the parameters in the case object happens, but somehow the compiler "knows" that overriding will happen, and it takes the default value for the parameter data type, which is zero in this case.
Why is it like this, and how can I use a superclass' parameterised require
clause from a case object when a parameter is overwritten in the object?
Your assumption about the order of execution and initialization is correct.
To get around this problem you have a few different options. One is to make every val
to be overridden a lazy val
, like so:
sealed abstract class C(val i: Int) {
protected lazy val min: Int = 1
protected lazy val max: Int = 5
require(i >= min && i <= max,
s"$i should be between $min and $max, inclusive")
}
case object O extends C(3) {
override protected lazy val min: Int = 3
override protected lazy val max: Int = 5
}
Another way to go is use the "early definition" syntax when overriding. The abstract class
code is unchanged but the object
looks like this.
case object O extends {
override protected val min: Int = 3
override protected val max: Int = 5
} with C(3)
A third option is to use "constant value definitions" but that tends to be more cumbersome and less convenient.
The details for all three options can be found at this FAQ.