5 ms·
A user of a library code such as this sometimes wants to catch all errors related to the library and doesn’t care whether they arose from a blocks.ParseError or
by rectang 4y ago
A user of a library code such as this sometimes wants to catch all errors related to the library and doesn’t care whether they arose from a blocks.ParseError or a blocks.DownloadError or whatever.
I like the granularity of this approach, especially that a function can indicate that it only errors out in some very specific way, such as a blocks.DownloadError.
But how do we get the best of both worlds — what would be the best way to gather together blocks.ParseError, blocks.DownloadError, etc. into a single blocks.BlocksError type?
- iudqnolq 4y agoTo a certain extent both approaches are viral. If your library uses the one big enum approach you'll want to add a DepFoo variant, and if you want to expose granular errors you'll need that info from your deps. I increasingly think the best of both worlds is either extreme, but never the middle ground. Either you actually need very granular errors or you should just use anyhow/eyre and have opaque errors with good human readable descriptions. The middle ground still takes a lot of work, but doesn't seem to give correspondingly better results
- rectang 4y agoAfter thinking this over, my inclination is to go to “both extremes” (I wouldn’t call it a “middle ground”). 1. Provide blocks.ParseError, blocks.DownloadError, etc. Individual functions use these, making it feasible to perform fine-grained error handling by matching on the type — as advocated in the article. 2. Provide a library-wide blocks.BlocksError non-exhaustive enum which is one layer of abstraction above the others and implements From for each of them. Define blocks.Result using this blocks.BlocksError. This allows users to write a function invoking library code which returns a blocks.Result, supporting the propagation use case. It doesn’t seem like adding blocks.BlocksError on top of the others is that much more work. The hard part is creating the localized modular error types.
- iudqnolq 4y agoIt's writing all the ParseError, DownloadError, etc that I'm suggesting you might want to avoid in certain cases Unfortunately due to the fundamental design of Rust error handling eyre & anyhow capture backtrace information at the moment their type is created. So the lower down you use it the better error messages you'll get. And "ParseError on line 134 in file foo.rs" can be much more valuable than "FooError on line 5 in file foo.rs: Caused by ParseError".