ADR-034: A Handler That Can Return Makes the Next Statement Conditional

Status: Superseded by ADR-292 — its D1 and D2 are not carried as rules there: they qualified the statement overlapping ADR-050 D1 displaced (D1 there); D1’s test survives as where the touch-set walk stops (D3 there) Amends: ADR-033 D5 — “no speculation” had one case it did not name Builds: ADR-033 §6’s first increment


1. Context

ADR-033 D5 forbids running an operation early that might not have run at all:

if x { read(a) } else { read(b) } starts one of them. Running both to save latency would burn a request that was never wanted.

It said conditional and meant a branch. Building the first increment found a second shape, and it is the one real Nikaia code is written in:

let a = fs::read_to_string("eins.txt") catch { return }
let b = fs::read_to_string("zwei.txt") catch { "".to_string() }

Both statements are unconditional as written. Neither is inside an if. The touch sets are disjoint — two different files, both read. Every rule in D2 says they may overlap.

They may not. If the first read fails, its handler leaves the function, and the sequential program never performs the second read at all. Overlapping them performs a read that the program as written would not have performed.

That is the thing D5 exists to prevent, arriving by a route D5 did not look down. catch is not a branch in the shape of an if, but a handler that can divert makes every statement after it conditional on the operation before it having succeeded.


2. Decision

D1 — A statement whose handler can leave the function is not overlapped with the one after it.

“Can leave the function” is any return or throw anywhere in the handler, however deeply nested. A handler that merely supplies a fallback value — catch { "".to_string() } — does not divert, and the pair may overlap.

The test is conservative in the direction ADR-033 D4 already set: a handler this compiler cannot see through keeps the order.

D2 — The general rule, stated so the next case does not need a third ADR.

D5 should have said, and now says:

An operation may be started early only if the program as written would certainly have performed it.

A branch is one way to be uncertain. A diverting handler is another. A break, a loop condition, and an early return between two statements are three more, and all of them are covered by the sentence rather than by a list.


3. Why it is worth its own record

It would have been easy to fix the code and say nothing — the restriction is four lines and a walk. Two reasons not to.

It is a correction to a decision made one day earlier, and ADR-033 is marked provisional partly because decisions of that size are expected to need them. A provisional decision that quietly acquires patches is no longer provisional; it is just vague.

It is the first evidence about ADR-033 that came from building rather than from thinking. ADR-033 §7 accepted a semantic decision without a measurement and owed something in return: that what building it teaches gets written down. This is the first instalment.


4. Consequences

This site is open source. Improve this page.