Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the difference between onComplete and foreach for a future in Scala?

I wonder the difference between onComplete and foreach when we use a Future in Scala.

f onComplete (_ => doSomething(_))

and

f foreach (_ => doSomething(_))

  1. Do the above lines of code lead to the same result?

  2. If I want to doSomething with Future f only after it's completed. What should I do? Should I use isCompleted like this:

    if(f.isCompleted) f onComplete (_ => doSomething(_))

Thank you guys a lot

like image 385
hminle Avatar asked Apr 23 '16 07:04

hminle


People also ask

Which method is used to execute the future in Scala?

The simplest way to create a future object is to invoke the Future. apply method which starts an asynchronous computation and returns a future holding the result of that computation. The result becomes available once the future completes.

What is Future and promise in Scala?

The Promise is a writable, single-assignment container that completes a Future. The Promise is similar to the Future. However, the Future is about the read-side of an asynchronous operation, while the Promise is about the write-side.

What Future sequence does?

This Future. sequence() function converts a list of Futures into a single Future that means collections of Futures into a single Future. In simple words, List[Future[T]] ======> Future[List[T]] . It is also known as composing Futures.

What is await result in Scala?

Await. result tries to return the Future result as soon as possible and throws an exception if the Future fails with an exception while Await. ready returns the completed Future from which the result (Success or Failure) can safely be extracted.


1 Answers

The main difference is the onComplete callback gets called even if the future completes with a failure, while foreach (and onSuccess) functions are called only in case of a successful result.

In fact, onComplete's parameter is a function Try[T] => U: the function you pass will be called with a Success[T] as argument if the future is successful or with a Failure if there was an exception:

val f = Future { ??? } // this future completes with a failure

// foreach only calls the callback if the future is successful
f.foreach(_ => thisWillNeverExecute()) 

// This will print "future failed" after the future completes
f.onComplete {
  case Success(_) => println("future completed successfully")
  case Failure(e) => println("future failed")
}

Also, you don't need to check anything to call the mentioned methods: onComplete/onSuccess/onFailure/foreach all schedule a callback that is called on the implicit ExecutionContext you have in scope, only when the future completes.

You can call them even if isCompleted is false, they will only be executed when the future completes successfully or fails, depending on which one you chose.

Let's have a look at their signatures:

def onComplete[U](@f: Try[T] => U)(implicit executor: ExecutionContext): Unit
  • onComplete takes a Try[T] => U function: this function will be executed on the implicit executor when the future completes. The argument will either be a Success[T] if the future is successful or a Failure if the future is failed

def onFailure[U](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Unit
  • onFailure parameter is a PartialFunction that is only executed on the implicit executor if the future fails with a Throwable for which pf is defined. It's basically the same as calling onComplete matching only some Failures, and in fact that is exactly how it is implemented in the standard library.

def onSuccess[U](pf: PartialFunction[T, U])(implicit executor: ExecutionContext): Unit
  • onSuccess parameter is, symmetrically to onFailure, a PartialFunction that is only executed on the implicit executor if the future completes successfully and the supplied PartialFunction is defined for the value.

def foreach[U](f: T => U)(implicit executor: ExecutionContext): Unit
  • foreach is basically the same as onSuccess but it takes a total function. This means that f is always executed if the Future completes successfully

N.B.: 'onSuccess' and 'onFailure' are going to be deprecated in 2.12. I suggest you read this series of posts by Viktor Klang to find out how you will be affected by the changes

like image 128
Giovanni Caporaletti Avatar answered Oct 13 '22 01:10

Giovanni Caporaletti