beps/docs/proposals/BEP-001-exceptions/legacy-ignore/ideas/alternative-syntax.md
This document explores "wild" alternatives to the Scoped Catch (Header) proposal, specifically addressing the feedback about Control Flow Inversion ("handle first, compute after") and Variable Access.
Instead of a static block at the top, on_error is an imperative statement that registers a handler for the current scope from that line forward.
function Process(id: string) {
// 1. Initial handler
on_error {
_: NotFound => return null
}
let user = db.getUser(id)
// 2. Register a new handler that HAS ACCESS to 'user'
on_error {
e => {
log.error("Failed processing user", { user: user, error: e })
throw e
}
}
// This risky operation is covered by the second handler
risky_operation(user)
}
on_error line anywhere without re-indenting.on_error statements, it can be hard to track which one is active. (Mitigation: on_error could stack or replace? "Defer" semantics?)catch (Expression Level)Attach error handling directly to the expression that might fail. This is similar to Ruby's rescue modifier or Perl's or die.
function Process(text: string) {
// Simple fallback
let data = extract(text) catch { return null }
// Complex handling with block
let result = risky_call() catch {
e: Timeout => retry()
e: AuthError => raise e
}
}
.catch() promises in JS.catch clauses (or wrap them in a block, re-introducing nesting).rescue (Implicit Try)Allow a rescue / catch block at the end of a function or scope. The entire scope is implicitly treated as the "try" block.
function Example() {
let x = 1
do_thing()
return x
} catch {
// Handles errors from the ENTIRE function body above
e: Error => {
log(x) // ⚠️ Scoping issue: is 'x' available?
return 0
}
}
let elseFocus on "ensuring success" rather than "catching failure". Inspired by Swift guard and Rust let else.
function Example() {
// "Ensure this succeeds, otherwise run this block"
guard let data = risky_call() else {
return null
}
// 'data' is safe to use here
process(data)
}
Move error handling completely out of the function body, into metadata.
@[Catch(TimeoutError, return: null)]
@[Catch(AuthError, strategy: "retry", attempts: 3)]
function Example() {
risky_call()
}
A dedicated block for attempting code and recovering.
function Example() {
let val = attempt {
risky_step_1()
risky_step_2()
} recover {
_: Timeout => null
e => throw e
}
}
try/catch nesting problem.