Scala Lesson 43 – Promises | Dataplexa

Promises in Scala

In this lesson, you will learn about Promises in Scala. Promises are closely related to Futures and give you explicit control over when and how a Future is completed.

While a Future represents a result that will arrive later, a Promise is the object that produces that result.


Future vs Promise

Understanding the difference between Futures and Promises is essential.

  • Future – read-only view of an asynchronous result
  • Promise – writable handle used to complete a Future

A Promise creates a Future, but only the Promise can complete it.


When Should You Use Promises?

Promises are useful when:

  • You need to complete a Future manually
  • The result depends on external events
  • You are integrating callback-based APIs
  • You want fine-grained control over async flow

Importing Promise

To use Promises, import them from the Scala concurrency package.

import scala.concurrent.Promise
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

Creating a Promise

You create a Promise using the Promise companion object.

val promise = Promise[Int]()

Each Promise is associated with a Future.


Getting the Future from a Promise

Every Promise exposes a Future using the future method.

val future = promise.future

Consumers interact with the Future, not the Promise.


Completing a Promise Successfully

To complete a Promise with a value, use success.

promise.success(100)

Once completed, the associated Future is also completed.


Completing a Promise with Failure

If an error occurs, complete the Promise with failure.

promise.failure(new RuntimeException("Something went wrong"))

The Future will now be in a failed state.


Observing the Future Result

You can attach callbacks to the Future created by a Promise.

future.onComplete {
  case scala.util.Success(value) =>
    println(s"Received: $value")

  case scala.util.Failure(error) =>
    println(s"Error: ${error.getMessage}")
}

Example: Promise with Background Task

This example completes a Promise after a background computation.

val promise = Promise[String]()
val future = promise.future

Future {
  Thread.sleep(1000)
  promise.success("Task completed")
}

future.foreach(println)

This pattern is useful for bridging synchronous and asynchronous code.


Completing a Promise Only Once

A Promise can be completed only once. Any further attempts will be ignored or throw an exception.

promise.success(10)
promise.success(20) // ignored or fails

Using trySuccess and tryFailure

To safely attempt completion without exceptions, use trySuccess or tryFailure.

promise.trySuccess(50)
promise.tryFailure(new Exception("Fail"))

These methods return true or false.


Promises vs Callbacks

Promises help replace deeply nested callbacks with cleaner code.

  • Better readability
  • Composable with Futures
  • Less error-prone

Common Use Cases

  • Wrapping legacy async APIs
  • Custom async workflows
  • Manual Future completion
  • Event-driven systems

📝 Practice Exercises


Exercise 1

Create a Promise that completes with a number after a delay.

Exercise 2

Complete a Promise with a failure and handle it.

Exercise 3

Use trySuccess to safely complete a Promise.


✅ Practice Answers


Answer 1

val p = Promise[Int]()
Future {
  Thread.sleep(500)
  p.success(99)
}
p.future.foreach(println)

Answer 2

val p = Promise[String]()
p.failure(new Exception("Error occurred"))

p.future.failed.foreach(println)

Answer 3

val p = Promise[Int]()
p.trySuccess(1)

What’s Next?

In the next lesson, you will learn about Akka Actors and how message-driven concurrency works in Scala.