Concepts / Exception Handling and Caught Exceptions

Exception Handling and Caught Exceptions

A promise is the sending side that matches a future's get(), providing put operations set_value() and set_exception().

  • Programming
Interactive lab

Try it: try / except / else / finally

How an exception jumps out of a try block to the first matching except clause, when else runs, and why finally always runs.

How it works

  1. Statements in try run until one raises an exception; the rest of try is skipped.
  2. Python checks the except clauses in order and runs the first one whose type matches.
  3. If nothing was raised, the else block runs instead.
  4. finally runs in every case.

Default run (9 steps): Call safe_divide('4'). … Return 25.0. Output was: Worked: 25.0 / Done.

Simplified: One fixed function; int() and / are modelled exactly (including how Python prints floats), but nothing is executed as Python.

Educational simulation

Loading the simulation…

Why a Result Needs a Route to a Reader

Programs often start work in one place and need the outcome in another. A task may compute a value in one part of the program while a different part is waiting for that value. The two parts need a way to pass the outcome from one to the other, and that outcome might be a normal result or the news that the work failed.

This article follows one question through the mechanism: when the producing code has a result, or when it has caught an error, how does that outcome reach the code that is waiting on it? Before reading on, try to predict the answer for yourself. If the work fails, what should the waiting side receive: a value, an exception, or nothing at all?

The Future and the Promise as a Pair

Definition

A promise is the sending side that matches a future's get(), providing put operations set_value() and set_exception().

A future is a place where a result will appear later. Someone has to put that result there, and someone else reads it out. The future is the reading side: it offers get() to retrieve the result. The promise is the writing side. Its main job is to provide simple put operations that match the future's get(). The two halves are designed to fit together, so a result produced in one place can be delivered to the future that another part of the program is waiting on.

The names future and promise are historical. They do not describe the mechanics perfectly, so it helps to think of them as a pair. The promise is the handle you use to send something in, and the future is the handle you use to take it out.

Key point

Think of the promise as the write side and the future as the read side. Whatever the promise sends, the future holds until get() is called.

The Promise-to-Future Channel

The flow works like a relay. A producing task creates a result of type X and places it in a promise. The promise forwards that outcome to the future through one of its two put operations, and the future hands it back when get() is called. The diagram below traces that path from the producer, through the promise and future, to the reader's get() call.

Producing taskcreates a result of type XPromisesending side, putoperationsFutureholds the outcomeget()reader takes the outcomeoutplaces outcomeput: set_value() or set_exception()outcome read by get()
How does a result travel from the promise side to the future side, and where does get() pick it up?

Notice where the outcome is read. The put comes from the sending side, and the get comes from the receiving side. The receiver's call to get() is what finally exposes the outcome. This is why the promise and the future must be matched: the operations on one side are designed to correspond to the operations on the other.

Sending a Value with set_value()

The value path is the ordinary case. The task finishes its work successfully, so it has a real result to give. It calls set_value() on the promise with that result, and the future now holds it. Later, a get() call on that future is where the value becomes visible to the reader.

Worked example

Tracing a successful task

A task computes the number 42 and must deliver it to a waiting reader through a promise and a future.

  1. 1
    Step 1: the task has a result

    The work finished normally, so the task holds a real result of type X, here 42.

  2. 2
    Step 2: the task calls set_value()

    The task passes 42 to the promise through set_value(), the put operation for a normal result.

  3. 3
    Step 3: the future holds the value

    The promise forwards the outcome to the future, which now holds 42.

  4. 4
    Step 4: the reader calls get()

    The reader calls get() on the future and receives 42 as the outcome.

Result

The reader receives the normal value 42 through get(). No exception is involved.

python
Notes on the code
  • This is pseudocode that mirrors the promise and future pairing described in the source, not a specific library's exact API.
  • set_value() is the put operation for a normal result.

When Work Fails: Sending an Exception

Sometimes the work does not succeed. Instead of a value, the promise must carry an exception to the future. The source names a helper for this situation: current_exception(). It refers to the exception that was caught. When the task has caught an error, current_exception() gives you a way to point at that caught exception so it can be passed along to the future.

The purpose is the same as the value path, but the payload is different. The future is still the place where the outcome will be read. The reader learns that something went wrong rather than receiving a normal result. The promise operation for this case is set_exception(), which sends the exception through the promise to the future.

python
Notes on the code
  • The try block holds the work that might fail.
  • The except block is the handling code that caught the error.
  • current_exception() refers to the caught exception, and set_exception() sends it to the future. This is a pseudocode illustration of the pattern in the source.

Choosing Between the Two Outcomes

Once the producing code has either a result or a caught error, the choice of promise operation is fixed. The rule from the source is that you pass either a value or an exception as the outcome, never both as a single outcome. The flowchart below shows the decision.

Did the worksucceed?Result of type Xnormal outcomeset_value(result)put a valueget() returns valueCaught exceptionwork failedcurrent_exception()refers to caught exceptionset_exception(...)put an exceptionget() reports failureyesfuture holds valuenofuture holds exception
When the producing code succeeds versus fails, which promise operation runs, and what does the future's get() return or throw in each case?

What do you think happens?

The producing code catches an error while doing its work. Which promise operation carries the outcome to the future?

  • set_value()

  • set_exception()

  • get()

Reveal answer
Answer:

set_exception()

The source describes set_exception() as the promise operation for passing an exception. get() belongs to the future, the reading side, not the promise.

Following a Caught Exception Step by Step

The sequence below follows the failure path from start to finish. The producing code hits a failure and the handler catches it. The handler uses current_exception() to name the caught exception, and set_exception() carries it through the promise to the future. A separate reader later calls get() to take the outcome out. The order of events is the same whether the put carried a value or an exception.

Producing codeHandlercatches the errorPromiseFutureReader1. work fails, error caught2. set_exception(current_exception())3. outcome stored in future4. get() later5. reader learns of failure
What happens step by step from the moment an exception is caught to the moment the future's get() reports it?
Worked example

Tracing a failed task

A task tries to parse a value and the parse fails. The waiting reader must learn that the work failed rather than receive a normal result.

  1. 1
    Step 1: the error is caught

    The handling code catches the error raised during the work.

  2. 2
    Step 2: name the caught exception

    current_exception() refers to the exception that was caught, so it can be handed onward.

  3. 3
    Step 3: send it to the future

    set_exception() places that exception into the promise's outcome, which the future now holds.

  4. 4
    Step 4: the reader calls get()

    When the reader calls get(), it learns the work went wrong instead of receiving a normal value.

Result

The waiting reader sees a failure outcome. No value is delivered for this outcome.

Mistakes When Pairing Promises and Futures

  • Common mistake

    Passing both a value and an exception as one outcome

    Why it fails

    The source says you pass either a value or an exception for a given result, never both as a single outcome.

    Do this instead

    Pick one put operation per outcome: set_value() for a normal result or set_exception() for a failure.

  • Common mistake

    Treating current_exception() as a general-purpose error reporter

    Why it fails

    current_exception() refers to the exception that was caught, and it makes most sense inside the handling code that caught it.

    Do this instead

    Call current_exception() in the handler where the error was caught, then pass its result to set_exception().

  • Common mistake

    Confusing the promise with the reading side

    Why it fails

    The promise is the sending side with put operations, while the future is the reading side that offers get().

    Do this instead

    Use set_value() or set_exception() on the promise, and call get() on the future.

  • Common mistake

    Assuming the names describe the mechanics exactly

    Why it fails

    The source notes that the names future and promise are historical and not meant to describe the mechanics perfectly.

    Do this instead

    Think of them as a matched pair: the promise sends the outcome in, and the future hands it out.

Practice Tracing the Outcome

EASY

A producing task finishes its work successfully and has the result 7. Describe which promise operation it calls, what the future holds afterward, and what get() returns to the reader.

Hints
  • Ask first whether the task has a normal result or a caught error.
  • A normal result uses the value path, and the promise operation for that path is named in the source.
  • The reader's get() exposes whatever the future holds.
MEDIUM

A handler catches an error during the work. Explain the full path of that outcome, naming current_exception(), the promise operation used, and what the reader learns when it calls get().

Hints
  • Start from the caught exception and follow it to the promise.
  • Remember the reader learns the work failed rather than receiving a normal result.

Key Takeaways

  • A promise is the sending side that matches a future's get(); the promise supplies put operations and the future supplies the reading operation.
  • A promise carries either a value, through set_value(), or an exception, through set_exception(), never both as a single outcome.
  • current_exception() refers to a caught exception and is used, inside the handling code, to send that exception to a future through set_exception().
  • The future holds the outcome until a reader calls get(), which is where the value or the failure becomes visible.

Related concepts

More concepts starting with E