I haven't often encountered code that requires this granularity of state resetting. While recognizing that this a toy example, I'm working to understand where this improves upon e.g.
func transitionStates() throws {
do {
stateA = try computeSix()
stateB = try computeSeven()
stateC = try computeNine()
try finishTransition()
} catch {
(stateA, stateB, stateC) = (0, 0, 0)
throw error
}
}
My impressions are:
- If the real-world replacement for
stateA = 0
(i.e. a state reset) is expensive, unconditionally resetting all states regardless of the failure point could be more costly; - In the circumstance that (1) holds, the existing syntactic alternative is, as described:
However, I think the syntactic burden of try
extends beyond the particular use case described here. Consider comparable code like this, which is deliberately un-nested:
func performSteps() -> Output {
let resultA: ResultA
do {
resultA = try stepA()
} catch {
return fallbackA
}
let resultB: ResultB
do {
resultB = try stepB(resultA: resultA)
} catch {
return fallbackB
}
// ...
}
The existing mechanism to un-nest sequential throwing operations with custom per-failure-point catch
handling introduces 1) an otherwise unnecessary type annotation and 2) a fair amount of syntax (do
/try
/catch
plus two sets of braces) for what roughly amounts to a throwing guard
statement.
This is recognizedly unergonomic ([1], [2], [3], [4], [5], ...), and I suspect a syntactic solution to this challenge would largely address the problem described here. Strawman:
func transitionStates() throws {
stateA = try computeSix() catch {
stateA = 0
throw error
}
stateB = try computeSeven() catch {
(stateA, stateB) = (0, 0)
throw error
}
stateC = try computeNine() catch {
(stateA, stateB, stateC) = (0, 0, 0)
throw error
}
try finishTransition()
}
Although this requires some duplication of cleanup logic:
- the order of operations is both unambiguous and linear (in contrast to sequenced
defer
blocks, which must be traced up backwards to interpret); - the syntactic burden is alleviated comparably to the proposed solution;
- the example captured by
performSteps()
above benefits equally from the new syntax.