Reputation: 8125
I have outlined the problem below. Method calculate
represents a calculation that is to run subCalc1
and subCalc2
asynchroniously, and mainCalc
that will be passed results from the last two 'sub' calculations. Significantly, before starting these calculations a preliminary calculation isCalcNecessary
is to return a Boolean. If true, the calculation will continue and eventually return Future[Some[Result]]. If preliminary calculation returns false, it should return Future[None], as to illustrate that calculation was not necessary. This small algorithm should be maximally asynchronious.
def isCalcNecessary:Future[Boolean] = ...
def subCalc1(param:Param):Future[SubResult1] = ...
def subCalc2(param:Param):Future[SubResult2] = ...
def mainCalc(subResult1:SubResult1, subResult2:SubResult2):Future[Result] = .
def calcute(param:Param):Future[Option[Result]] = for {
necessary <- isCalcNecessary(param)
if necessary // this illustration fails at runtime if 'necessary' is false
subResult1 <- subCalc1(param)
subResult2 <- subCalc2(param)
result <- mainCalc(subResult1, subResult2)
} yield Some(result)
The above illustration fails at runtime with (NoSuchElementException: Future.filter predicate is not satisfied (Future.scala:312)
), if the if necessary
conditional is not satisfied.
How would you write this algorithm?
Upvotes: 0
Views: 161
Reputation: 7373
Another option would be to nest for-comprehensions
def calculate(param:Param):Future[Option[Result]] = for {
necessary <- isCalcNecessary(param)
endResult <- if (necessary) for {
subResult1 <- subCalc1(param)
subResult2 <- subCalc2(param)
result <- mainCalc(subResult1, subResult2)
} yield Some(result)
else future(None)
} yield endResult
Upvotes: 2
Reputation: 170735
isCalcNecessary(param).flatMap { necessary =>
if (necessary)
for {
subResult1 <- subCalc1(param)
subResult2 <- subCalc2(param)
result <- mainCalc(subResult1, subResult2)
} yield Some(result)
else
future(None)
}
Upvotes: 2