I'm writing a Scala application using ReactiveMongo driver. The methods that access to the db return always Future[T]
. Are the following pieces of code equivalent?
(With onComplete
)
val results: Future[List[Tag]] = Tags.all.toList
results onComplete {
case Success(list) => //do something with list
case Failure(t) => //throw the error
}
(With flatMap
)
Tags.all.toList.flatMap(list => //do something with list)
What's the difference?
The flatMap doesn't throw the Failure?? And the flatMap
is a callback like onComplete
or wait until the Tags.all.toList
statement doesn't complete?
When in doubt, follow the types.
onComplete
returns Unit
, it allows you to do something with the Future
result, but it won't return a value
flatMap
allow you do something with the list and return a new Future
So flatMap
is much more powerful as it allows you to chain multiple futures, doing something with their values along the way, and handling the failure case only at the very end. To use Erik Meijer's words: "it guides you through the happy path".
So for instance you can do
val finalFuture = results
.flatMap(x => /* do something and return a future */)
.flatMap(y => /* do something else and return a future */)
.flatMap(z => /* do something else and return a future */)
.map(myresult => /* do something */)
If something goes wrong along the way, the chain is broken early and you'll get the first error occurred.
This allows for an even nicer syntax
val finalFuture = for {
x <- results
y <- /* do something and return a future */
z <- /* do something and return a future */
} yield something(z)
If you need to handle the failure case, you can now use onComplete
, or - even better - simply return the Future
as it already contains the information on whether the async computation succeeded or not.