What's the difference between onComplete and flatMap of Future?

alberto adami picture alberto adami · Oct 14, 2014 · Viewed 11.2k times · Source

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?

Answer

Gabriele Petronella picture Gabriele Petronella · Oct 14, 2014

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.