|
|
|
|
|
by tux3
1777 days ago
|
|
What do you think of languages that use sum types for error handling, but can still unwind in a few scenarios? Reasonnable compromise, or should we get rid of all unwinding always? And if so, do we abort() or do we ask users to handle any and all possible errors. |
|
The usual way control flow progresses is forwards, but when an error occurs, it goes backwards, over the defers and errdefers.
C++ exception handling and other languages with destructors force you to do this declaratively, but then don't give enough control over exactly the situations they matter in: setup and teardown.
Meanwhile with explicit control, you just encode exactly what happens in the "backwards" control flow. No surprises, no trying to figure out what happens based on declarative rules. Once I figured this out, I was able to use it to simplify the logic of some things in the self-hosted compiler that are extremely error prone in the C++ implementation:
* Lazy source locations: passing in "none" for a source location, and then handling the "error.SourceLocationNeeded" and then doing the expensive calculations to find the source locations before retrying the operation.
* Generic instantiations: returning "error.GenericPoison" for when a type parameter cannot be determined without information from the callsite. In this case, the analysis is cleanly aborted and function marked as generic.
I'm pleased with how this turned out, and I've started to think of other languages in terms of how they map to this "forwards" and "backwards" control flow concept.