I may want to use a method that is expensive and returns a result depending on side effects. For example depending on the time of day / week and a Monte Carlo simulation of quantum chronodynamics. Because it's expensive and I may not need it, I'll use Scalas lazy val
lazy val maybeUnusedValue = getDayOfWeek
Now 12 hours pass with my program still running. I want to redo the calculation, because my day may have changed in the meantime.
Is there a simple way to force Scala to return maybeUnusedValue
back to uninitialized state, therefore forcing a recalculation on its next usage?
Is there a simple way
Since "laziness" is implemented with a field to track initialization, the simple solution is to wrap the lazy val with a mutable reference. You'll have to deal with mutability of that reference, of course.
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
You are running into two problems:
val
is immutable, i.e. cannot be changed after initializationvar
instead, it has no mechanism to expire after some timeMy suggestion would be turn getDayOfWeek
into a function that tracks 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 of when to recompute is a bit hacky, so you'll want to come up with your own, but the basic gist is that you calculate on demand.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With