Lazy Val - How to reset the value?

I can use an expensive method and return the result depending on the side effects. For example, depending on time of day / week and Monte Carlo simulation of quantum chronodynamics. Because it is expensive and I may not need it, I will use Scalaslazy val

lazy val maybeUnusedValue = getDayOfWeek

      

Now my program is still running 12 hours. I want to repeat the calculation because my day may have changed during this time.

Is there an easy way to force Scala to revert maybeUnusedValue

back to an uninitialized state, and therefore forcing it to be recalculated for the next use?

+3


source to share


2 answers


Is there an easy way

Since "laziness" is implemented with a field to keep track of initialization, a simple solution is to wrap the lazy val with a mutable reference. You will of course have to deal with the volatility of this link.

scala> class V { lazy val v = System.currentTimeMillis }
defined class V

scala> @volatile var x = new V
x: V = V@77468bd9

scala> x.v
res0: Long = 1431212391127

scala> x.v
res1: Long = 1431212391127

scala> x = new V
x: V = V@28f67ac7

scala> x.v
res2: Long = 1431212407970

      



and then something like

scala> import concurrent._, duration._, ExecutionContext.Implicits.global
import concurrent._
import duration._
import ExecutionContext.Implicits.global

scala> implicit class ex(val d: Deadline) extends AnyVal { def expiring(f: => Unit) =
     | Future(Await.ready(Promise().future, d.timeLeft)) onComplete (_ => f) }
defined class ex

scala> 10 seconds fromNow expiring { x = new V }

scala> x.v
res4: Long = 1431212407970

scala> x.v
res5: Long = 1431212407970

scala> x.v
res6: Long = 1431213010180

      

+7


source


You have two problems:

  • val

    immutable, that is, it cannot be changed after initialization
  • even if you used it var

    instead, it has no mechanism to expire after a while

My suggestion would turn getDayOfWeek

into a function that keeps track of the current value and state in some other instance:



private var dayOfWeek: Option[Day] = None
private var lastEvaluated: Int = 0

def getDayOfWeek = dayOfWeek match {
  case None => expensiveGetDayOfWeek
  case Some(day) =>
    if (DateTime.now.getDayOfYear > lastEvaluated) expensiveGetDayOfWeek
    else day

}

private def expensiveGetDayOfWeek: Day = {
  dayOfWeek = Some(someExpensiveOperation())
  lastEvaluated = DateTime.now.getDayOfYear
  dayOfWeek.get
}

      

My state tracking for when to overcommit is a bit of a hack so you have to come up with your own, but the main point is that you compute on demand.

+2


source







All Articles