Swiftorial Logo
Home
Swift Lessons
Matchups
CodeSnaps
Tutorials
Career
Resources

Futures and Promises in Scala

Introduction

Futures and Promises are fundamental constructs in Scala that enable asynchronous programming. They allow you to write non-blocking code that can perform multiple tasks concurrently. A Future represents a value that may not yet be available, while a Promise is a writable, single-assignment container that can be used to create a Future.

What is a Future?

A Future is a placeholder for a value that is computed asynchronously. When you call a method that returns a Future, you can continue executing other code while waiting for the result. Futures are often used for operations that might take a long time, such as network requests or heavy computations.

Example of a Future:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
val future: Future[Int] = Future { 42 }
Future()

In this example, a Future is created that will eventually hold the integer 42. The computation (in this case, just returning 42) is performed in a separate thread.

What is a Promise?

A Promise is a writable, single-assignment container that can be used to complete a Future. When you complete a Promise, the associated Future is completed with the value or exception provided.

Example of a Promise:

import scala.concurrent.Promise
val promise = Promise[Int]()
promise.success(42)
val future: Future[Int] = promise.future
Future(42)

In this example, a Promise is created, and then it is completed successfully with the value 42. The associated Future reflects this completed state.

Using Futures and Promises

You can use Futures and Promises together to manage asynchronous computations effectively. For instance, you might start a computation and return a Future, while using a Promise to signal when the computation has completed.

Example of Combining Futures and Promises:

import scala.concurrent.{Future, Promise}
import scala.concurrent.ExecutionContext.Implicits.global
def asyncComputation(): Future[Int] = {
val promise = Promise[Int]()
Future {
Thread.sleep(1000)
promise.success(42)
}
promise.future
}
Future()

In this example, the asyncComputation function creates a Promise and starts a Future that will complete the Promise after sleeping for one second. The function returns the Future associated with that Promise.

Handling Results

Once you have a Future, you can handle its result using callbacks. The onComplete, onSuccess, and onFailure methods let you define what to do when the Future completes.

Example of Handling Future Results:

val future: Future[Int] = Future { 42 }
future.onComplete { case Success(value) => println(s"Got the result: $value") }
future.onFailure { case e: Throwable => println(s"An error has occurred: ${e.getMessage}") }
Got the result: 42

This example demonstrates how to handle the result of a Future. The onComplete method is called when the Future is completed, either successfully or with an error.

Conclusion

Futures and Promises provide a powerful way to handle asynchronous programming in Scala. By using these constructs, you can write non-blocking code that is easier to manage and understand. Remember to always handle exceptions properly and consider using combinators like map and flatMap to work with Futures more effectively.