Scala, initializing abstract vals

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
}
+4
source share
1 answer

(. . 453 Scala, 3- .):

trait A { 
  val x: Int 
  lazy val y: Int = x
  val z: Int = y 
}

new A { val x = 1 }.y        // ==0 ?!!!
new A { val x = 1 }.z        // ==0 ?!!!

trait A { 
  val x: Int 
  val y: Int = x
  val z: Int = y 
}

new A { lazy val x = 1 }.y   // ==1
new A { lazy val x = 1 }.z   // ==1

, , val . -, , x def, , .

+1

Source: https://habr.com/ru/post/1650071/


All Articles