Scala Programming, Third Edition, Martin Odersky, gives this example on page 449:
trait RationalTrait {
val numerArg: Int
val denomArg: Int
require(denomArg != 0)
private val g = gcd(numerArg, denomArg)
val numer = numerArg / g
val denom = denomArg / g
private def gcd(a: Int, b: Int): Int =
if (b == 0) a else gcd(b, a % b)
override def toString = numer + "/" + denom
}
and then it is explained that the following code does not work, because the flag is initialized before the anonymous class, and therefore denomArg is still 0.
new RationalTrait {
val numerArg = 4
val denomArg = 24
}
and it provides two solutions. One solution is to use pre-initialized fields:
new {
val numerArg = 4
val denomArg = 24
} with RationalTrait
the second solution is to change the tag to use lazy values as follows:
trait LazyRationalTrait {
val numerArg: Int
val denomArg: Int
lazy val numer = numerArg / g
lazy val denom = denomArg / g
override def toString = numer + "/" + denom
private lazy val g = {
require(denomArg != 0)
gcd(numerArg, denomArg)
}
private def gcd(a: Int, b: Int): Int =
if (b == 0) a else gcd(b, a % b)
}
new LazyRationalTrait {
lazy val numerArg = 4
lazy val denomArg = 24
}
However, this simpler solution also works. I wonder why they did not mention this decision. Is there a flaw in this?
new RationalTrait {
lazy val numerArg = 4
lazy val denomArg = 24
}
source
share