Is it correct behaviour that `lazy val` acts like `def` in case of exception?

I've noticed that lazy val repeats computation several times (in case of exception):

scala> lazy val aaa = {println("calc"); sys.error("aaaa")}
aaa: Nothing = <lazy>

scala> aaa
calc
java.lang.RuntimeException: aaaa
  at scala.sys.package$.error(package.scala:27)
  at .aaa$lzycompute(<console>:7)
  at .aaa(<console>:7)
  ... 33 elided

scala> aaa
calc
java.lang.RuntimeException: aaaa
  at scala.sys.package$.error(package.scala:27)
  at .aaa$lzycompute(<console>:7)
  at .aaa(<console>:7)
  ... 33 elided

Shouldn't it be like:

scala> aaa
calc
java.lang.RuntimeException: Not Initialized! 
caused by
java.lang.RuntimeException: aaaa

scala> aaa
java.lang.RuntimeException: Not Initialized! 
caused by
java.lang.RuntimeException: aaaa  

Answers


In this post they explain very well how lazy val is compiled by the Scala compiler. Basically, if the evaluation of the expression fails, then the indicator-bit signaling that the lazy val contains its data won't be set.

update1:

I think one reason going with the first approach could be that the second one may be emulated by using two lazy vals, without burdening the underlying implementation with multiple volatile variables:

scala> lazy val _aaa = Try {println("calc"); sys.error("aaaa")}
_aaa: scala.util.Try[Nothing] = <lazy>

scala> lazy val aaa = _aaa.get
aaa: Nothing = <lazy>

scala> aaa
calc
java.lang.RuntimeException: aaaa
  at scala.sys.package$.error(package.scala:27)
  at $anonfun$_aaa$1.apply(<console>:10)
  at $anonfun$_aaa$1.apply(<console>:10)
  at scala.util.Try$.apply(Try.scala:191)
  at ._aaa$lzycompute(<console>:10)
  at ._aaa(<console>:10)
  at .aaa$lzycompute(<console>:11)
  at .aaa(<console>:11)
  ... 33 elided

scala> aaa
java.lang.RuntimeException: aaaa
  at scala.sys.package$.error(package.scala:27)
  at $anonfun$_aaa$1.apply(<console>:10)
  at $anonfun$_aaa$1.apply(<console>:10)
  at scala.util.Try$.apply(Try.scala:191)
  at ._aaa$lzycompute(<console>:10)
  at ._aaa(<console>:10)
  at .aaa$lzycompute(<console>:11)
  at .aaa(<console>:11)
  ... 33 elided

update2:

As @Silly Freak has proposed in his comment,

scala> lazy val _aaa = Try {println("calc"); sys.error("aaaa")}
_aaa: scala.util.Try[Nothing] = <lazy>

scala> def aaa = _aaa.get
aaa: Nothing

may work even better, as we can avoid having two lazy vals.


Need Your Help

Java: How to get n elements from a set

java set java-8

I was trying to find the most elegant way to get the n elements from a set starting from x. What I concluded was using streams:

More Efficient Conversion of Archived Python Dict to JSON

python json gzip converter abstract-syntax-tree

I have a lot of archive data in python dict format that I am working to convert over to json. I'm interested in speeding this process up if I can and would like to know if anyone has any suggestions.