Reputation: 3367
This is a theoretical question. I have a service I can call to do a job, but that service might not do all of it, and thus I will need to call a second one to finish it.
I was wondering if there is a way to do something similar to this without Await.result
the result within the map function:
val myFirstFuture = asyncRequestA()
myFirstFuture.map(result => {
result match {
case isWhatIExpected => result
case isNot => Await.result(asyncRequestB(), someDuration)
}
})
I would like to "merge" the future given by asyncRequestB()
into myFirstFuture
without using the Await function to get the result.
Any ideas?
Upvotes: 3
Views: 1352
Reputation: 32719
Just use flatMap
instead of map
:
myFirstFuture.flatMap{ result =>
result match {
case isWhatIExpected => Future.successful( result )
case isNot => asyncRequestB()
}
}
As a side note, you can even shorten it like this:
myFirstFuture.flatMap{
case result: isWhatIExpected => Future.successful( result )
case _ => asyncRequestB()
}
See also Nikita Volkov's answer for an example of using for comprehensions
Upvotes: 5
Reputation: 43309
Future
is a monad. And the standard way of working with monads in Scala is using a "for comprehension":
for {
firstResult <- firstFuture
secondResult <- firstResult match {
case isWhatIExpected => Future.successful( firstResult )
case isNot => asyncRequestB()
}
}
yield secondResult
In Scala "for comprehension" is a syntactic sugar for a series of flatMap
, map
and filter
method applications and under the hood the compiler will expand this comprehension into the same thing as in Regis' answer.
Although in this case you might not exactly see the benefit from using a "for comprehension" syntax, when you drop in another Future
and when things start getting trickier, it will come to shine. What "for comprehension" basically does is it flattens the otherwise many levels of nesting of those three method applications.
Secondly, there's also a way you could optimize Regis' solution syntactically, by utilizing "partial functions":
myFirstFuture.flatMap{
case r if isWhatIExpected( r ) => Future.succesful( r )
case r if isNot( r ) => asyncRequestB()
}
Upvotes: 6