9 ms·
Trying to get error backtraces in Rust libraries right
- AstralStorm 1y agoMore on how best practices in Rust are not documented anywhere but in a bunch of unfindable blog posts. :( And even then, there's no guarantee what you find is not outdated.
- tialaramex 1y agoI'm not sure how this idea makes coherent sense. Best practices are going to be determined by users, so even in a language where there's a BDFL or some ludicrous committee flying to Hawaii to discuss everything in person a central "Best practice" document is not actually best practices it's just somebody's opinion but with a rubber stamp. A central dogma approach just means you need more doublethink, the "best practices" still gradually change but now you're pretending they've always been this way even as they shift beneath your feet.
- m11a 1y agoThink you need a healthy mix? eg: if you want distributed systems, esp Java-style, https://www.martinfowler.com https://www.martinfowler.com is a pretty handy reference. (similar for other areas of SWE). It’s nice to have a single resource that documents a bunch of non-obvious but still-generally-accepted engineering practices relevant to a domain. It’s of course an opinion, but is reasonably uncontroversial. Or at least, you won’t go too wrong while you develop your own taste in said domain.
- tayo42 1y agoSomething like pep8 is useful. I get what poster means. Everytime I come back to rust I find it hard to know what the latest thing and way to do something is.
- m11a 1y agoFor Rust, there are a few blogs that lean more on fundamentals and language design (like https://without.boats/blog https://without.boats/blog, https://smallcultfollowing.com/babysteps https://smallcultfollowing.com/babysteps). For misc Rust engineering, like the OP, I agree it’s quite scattered. I personally like to save good ones in my Feedbin as I encounter them
- imtringued 1y agoThis has very little to do with Rust. The entire software development industry has slept on error handling without exceptions and Rust developers are the first ones to actually start addressing the problems. This problem should have been solved decades ago by C/C++ developers.
- baq 1y agoThey are not first by any means, but the popular languages definitely focus on the happy path with varying but consistently insufficient degrees of enforcement of handling deviations… because that’s easy to iterate on. Java e.g. would benefit from a strict null mode, but the legions of half baked ‘engineers’ wouldn’t comprehend how to write software when you can’t initialize a reference to null and only set it later.
- csomar 1y agoRust has the Error type. Libraries are add-ons and not part of the language.
- tialaramex 1y agoWell, Rust's standard library provides two types named Error, their full names are core::fmt::Error (aka std::fmt::Error) and std::io::Error But, neither of these is intended as "the" error type - unless you're a formatter or an I/O abstraction they're not the error types you want. Rust provides a trait core::error::Error (aka std::error::Error) and that might be what you're thinking about. It's recommended that your own private error type or types should implement this trait but nothing requires this in most contexts.
- sbt 1y ago> The core issue is that Rust still hasn't stabilized backtrace propagation on errors. I would actually strengthen this to: «The core issue with Rust is that Rust still hasn’t stabilized _»
- tialaramex 1y agoReally? Premature stabilization is a much more recognisable problem. This is after all quietly why there's so much Rust adoption. Safety is nice, but perf is $$$. C++ had this unhealthy commitment to stabilization and it meant that their "Don't pay for what you don't use" doctrine has always had so many asterisks it's practically Zalgo text or like you're reading an advert for prescription medicine. You're paying for that stabilization, everywhere, all the time, and too bad if you didn't need it. Unwinding stabilizations you regret is a lot more work even in Rust, consider the Range types, landing improved Range types is considerable work and then they'll need an Edition to change which types you get for the syntax sugar like 1..=10 Or an example which happened a long time ago, the associated constants. There are whole stdlib sub-packages in Rust which exist either primarily or entirely as a place for constants of a type, std::f32::MAX is just f32::MAX but the associated constant f32::MAX only finally stabilized in 1.43 so older code uses std::f32::MAX nevertheless if you learned to write std::f32::MAX you may only finally get deprecation messages years from now and they're stuck with keeping the alias forever of course because it's stable.
- nromiun 1y agoI remember people being so excited to use error values instead of exceptions in mainstream languages. But this libraries plus error values combo looks even more complex to me.
- csomar 1y agoIt is not more complex. It is a complex problem and raising exceptions is akin to just giving up (vs. properly handling and reporting the errors).
- nromiun 1y agoThat is akin to saying using a GC is giving up on safe memory allocation, and the borrow checker is the only solution to a complex problem. Exceptions are handled gracefully in real world projects as well, otherwise Python, Java etc would have died a long time ago.
- csullivannet 1y agoMaybe this is my Golang dev leaking, but I intuitively thought that `try: / except:` in Python is essentially the same thing as `if err != nil`, just my IDE doesn't scream at me if I don't catch them.
- tcfhgj 1y agoMaybe you are not giving that up, but you are giving up doing memory management "properly", i.e. use more memory and CPU time than necessary for convenience.
- quotemstr 1y agoAnd we slowly circle back to what Rust should have done all along: exceptions with Java/Python-style causal chaining. I wonder how loudly "the community" would scream at me if I published something that just used panics for all error reporting.
- ninkendo 1y agoExcept the java/python style with unchecked exceptions means an exception can happen at any time, there's no way to know in advance. This is what Rust is trying to avoid with the errors-as-values approach. It has its drawbacks, yes, but I'd never go back to the wild-west YOLO approach of unchecked exceptions, personally.
- zaphar 1y agoTo be fair, Rust could have done CheckedExceptions like Java has but no one uses. The problematic version is the RuntimeException. I think the real problem was that when Rust conceived of Result they didn't constrain the problem to just error handling and made it a little bit too much "anything goes". Which means that trying to shoehorn backtraces in after the fact with `?` and `try_into` is now hard. There could have been a world where `Result::Err` was actually a wrapper type that specified an optional source error for backtracing and the generic type was embedded in that instead. It would have been less flexible but it would have made proper backtraces more tractable.
- ninkendo 1y agoIs there a language that has proper exclusively checked exceptions? That is, not just syntax sugar around checking an error value (à la Swift), but actual “the processor signals an exception” semantics, but all exceptions are still enforced to be handled-or-passed by the compiler? Honest question, because I can’t think of any. I can see it being advantageous to have checked-only exceptions but there has to be a good reason why it’s so rare-to-never that we see it. I’m not sure how else you’d get the holy grail, which I’d define as: 1. The compiler enforces that you either handle an exception or pass it to the caller 2. Accurate and fine-grained stack traces on an error (built-in, not opt-in from some error library du jour) 3. (ideally) no runtime cost for non-exception paths (no branches checking for errors, exceptions are real hardware traps) C++ has 2 and 3, Java has only 2 (because RuntimeException exists), Rust has only 1. I’d love a language with 1 and 2, but all 3 would be great.
- conaclos 1y agoThe following articles may also be of interest to the audience: - The definitive guide to error handling in Rust [0] - Error Handling for Large Rust Projects - Best Practice in GreptimeDB [1] - Designing error types in Rust [2] - Modular Errors in Rust [3] [0]: https://www.howtocodeit.com/articles/the-definitive-guide-to-rust-error-handling https://www.howtocodeit.com/articles/the-definitive-guide-to... [1]: https://greptime.com/blogs/2024-05-07-error-rust https://greptime.com/blogs/2024-05-07-error-rust [2]: https://mmapped.blog/posts/12-rust-error-handling https://mmapped.blog/posts/12-rust-error-handling [3]: https://sabrinajewson.org/blog/errors https://sabrinajewson.org/blog/errors
- b_e_n_t_o_n 1y agoIdk, I'd take if err != nil { return nil, err } over any of this :)
- throwawayqqq11 1y agoAnd now you introduce null and err checks all over your code base. Rust tries to do this ergonomically with the ?-operator, which is not that easy in complex cases but reduces your cognitive load tremendously when possible.