I went back and forth on this for a long time. Lua's exception mechanism is actually pretty fast but they're just strings, so there's no useful information unless you match on those strings (eek!)
I think encoding these things into a better type signature is the way to go. In Go and Lua, that means multiple return values like `success, result` or `result, err`. It's pretty clunky and verbose in both of those languages though and so my years of Lua made me instantly skeptical of Go doing the same thing.
Languages with cheap data-carrying enums like Rust are my favourite these days. No unhandled exceptions, super obvious where the failure is, and Rust has a lot of niceties for handling, mapping, and adding context to errors without a lot of runtime cost.
I think encoding these things into a better type signature is the way to go. In Go and Lua, that means multiple return values like `success, result` or `result, err`. It's pretty clunky and verbose in both of those languages though and so my years of Lua made me instantly skeptical of Go doing the same thing.
Languages with cheap data-carrying enums like Rust are my favourite these days. No unhandled exceptions, super obvious where the failure is, and Rust has a lot of niceties for handling, mapping, and adding context to errors without a lot of runtime cost.