thiserror helps a bit with conciseness. But it’s still the most annoying part of writing Rust for me, even more annoying than async closure capture semantics, and one that I happily offload to deepseek whenever I have to write it. I was even thinking of making some insane proc_macro that would traverse a function and extract the list of all ?, deduce the types, and come up with the final error type (maybe with some hints). But this turned out to be too difficult for a weekend project and ain’t nobody wants to pay me to write it.
Type-safe: can’t beat errors as enum values wrapped in Result.
I’m talking more about the anyhow-style here. It’s not very type-safe.
Composable: i don’t think you can beat rust enums in composability.
Well, thiserror-style enums are composable-ish, but they can be too structured for their own good. Sometimes you want only a particular property of an error (e.g. one of the HTTP requests returned 429 or something), and don’t care about the particular branch of the call tree it came from. Rust doesn’t really have the compile-time flexibility to write such a check without a ton of boilerplate that will also break once the call tree changes.
thiserror helps a bit with conciseness. But it’s still the most annoying part of writing Rust for me, even more annoying than async closure capture semantics, and one that I happily offload to deepseek whenever I have to write it. I was even thinking of making some insane proc_macro that would traverse a function and extract the list of all
?, deduce the types, and come up with the final error type (maybe with some hints). But this turned out to be too difficult for a weekend project and ain’t nobody wants to pay me to write it.I’m talking more about the
anyhow-style here. It’s not very type-safe.Well, thiserror-style enums are composable-ish, but they can be too structured for their own good. Sometimes you want only a particular property of an error (e.g. one of the HTTP requests returned 429 or something), and don’t care about the particular branch of the call tree it came from. Rust doesn’t really have the compile-time flexibility to write such a check without a ton of boilerplate that will also break once the call tree changes.