I have an abstract trait with some requirements for calculations that are hard, and then some functions on the results of those calculations. I want to keep this trait simple so that it is easy to understand and test.
trait Calculator {
def hardToCalculate1: Int
def hardToCalculate2: Int
def hardToCalculate3: Int
def result1 = hardToCalculate1 + hardToCalculate2
def result2 = hardToCalculate2 + hardToCalculate3
def result3 = hardToCalculate1 + hardToCalculate3
}
When I instantiate a Calculator
, I'm going to use Futures to calculate those hardToCalculate
values. Let's say they look like this:
def f1 = future {
println("calculating 1")
1
}
def f2 = future {
println("calculating 2")
2
}
def f3 = future {
println("calculating 3")
3
}
So, I can construct a Future[Calculator]
like this:
val myCalc = for {
m1 <- f1
m2 <- f2
m3 <- f3
} yield new Calculator {
lazy val hardToCalculate1 = m1
lazy val hardToCalculate2 = m2
lazy val hardToCalculate3 = m3
}
Then, I might use myCalc
like this:
myCalc onComplete {
case Success(calc) => println("Result: " + calc.result1)
}
But when I do, I get this:
calculating 1
calculating 2
calculating 3
Result: 3
I'd like to only execute those futures if they are actually needed by the calculation I'm making. Even though I declared the hardToCalculate
s with lazy val
, all three are calculated when the Future[Calculator].onComplete
is executed.
One way to do this would be like this:
val calculator = new Calculator {
lazy val hardToCalculate1 = Await.result(f1, 10 seconds)
lazy val hardToCalculate2 = Await.result(f2, 10 seconds)
lazy val hardToCalculate3 = Await.result(f3, 10 seconds)
}
println("result: " + calculator.result1)
This produces what I want:
calculating 1
calculating 2
result: 3
But now I have all of that Await
blocking. What I really want is a Future[Calculator]
that will execute the futures in a lazy way. Is this possible without introducing Futures into my Calculator
trait? Any other suggestions about how to get what I'm after here?