8 ms·
I appreciate the author's efforts and amount of time that went into this. But, IMHO, there are some things that are just plain bad advice: e.g. https://www.lur
by morning-coffee 3y ago
I appreciate the author's efforts and amount of time that went into this. But, IMHO, there are some things that are just plain bad advice:
e.g. https://www.lurklurk.org/effective-rust/panic.html https://www.lurklurk.org/effective-rust/panic.html
"Another sensible use of panic!, even in library code, is in situations where it's very rare to encounter errors, and you don't want users to have to litter their code with .unwrap() calls."
The litmus test for panic! vs. Result<T,E> is not rarity of occurrence, it's whether the condition represents a programming bug or a recoverable error. A good treatise on this topic here: https://joeduffyblog.com/2016/02/07/the-error-model/#bugs-arent-recoverable-errors https://joeduffyblog.com/2016/02/07/the-error-model/#bugs-ar...
- klysm 3y agoIf you are writing a library, whether or not .unwrap() is sensible is not up to you - it's up to the user.
- photonbeam 3y agoIs there a tool that can assert a library doesnt/cant panic?
- morning-coffee 3y agohttps://docs.rs/no-panic/latest/no_panic/ https://docs.rs/no-panic/latest/no_panic/ might be what you're looking for
- ajross 3y agoJust to jump in from the peanut gallery: this kind of discussion, about the "right" way to do things in a complicated language with lots of choice, prompting digressions about conventions and mildly-kludgey third party "soft" solutions to what would seem to be generic problem... ...is exactly where C++ was in 1995 when Meyers published Effective C++. The specifics of the argument notwithstanding, the very existence of this discussion validates the need for this book. And it also says some somewhat awkward things about the direction in which Rust is evolving.
- Joker_vD 3y agoSo, what's actually the correct answer? Or should we go and read the whole book?
- ajross 3y agoThe joke is that there is no correct answer, and there "should" be, which is why Rust needs books now. Things always get worse and not better over time in this space.
- shrimp_emoji 3y agoInstead of old and wise, languages only get old and senile. :D (For which there is but one cure: breaking backwards compatibility.)
- sophacles 3y agoThis discussion exists for any programming language that qualifies for the label "useful for 1 or more tasks".
- ajross 3y agoNot at this level of pontification. Python and C and Java and .NET have achieved much success without this kind of "the community can't decide on the right way to do this very fundamental thing[1]" kind of disconnect, largely by scoping themselves such that the tradeoffs are made internally to the language runtime and not a subject for debate. And, fine, Rust is more ambitious, just like C++ was. But that too has tradeoffs in language complexity and evolutionary cruft, something that is often cited as an advantage vs. C++. But as we're seeing here, it's not really. It's just that C++ is a few decades farther along on the same curve. [1] In this case, literally, how to handle a runtime error.
- burntsushi 3y agoThis is absurd. The community has decided. Go look at any popular Rust library. The panicking strategy will be the same in all of them: if a panic actually occurs at runtime, it's considered a bug. But libraries still use unwrap in the same way asserts are used. I've asked many people to show me real Rust code that does it differently, and I haven't found any takers. The confusion here is mostly in terminology and in the "peanut gallery." This has literally been a solved problem since Rust 1.0. I know because I was there and published a blog post on exactly this topic.
- burntsushi 3y agoThis is wrong. Plenty of Rust libraries, including std, correctly use unwrap: https://blog.burntsushi.net/unwrap/ https://blog.burntsushi.net/unwrap/
- cornstalks 3y agoYou have a point but so does the OP. The classic example that follows the OP's recommendation is allocation failures. Of course, not everyone is happy that String or Vec will panic on allocation failure and wish allocating methods returned a Result instead. But changing all allocating APIs to returning a Result would make others unhappy given how rarely a program can truly recover from an allocation failure.
- pornel 3y agoBTW, overcommit/oomkiller aside, recovery from allocation failure in Rust can be easy and reliable. There is an assumption carried over from C that code paths handling OOM errors are untested and likely broken. However, Rust doesn't have manually-written error handling paths like that. It has `Drop` which is always correctly inserted by the compiler, and regularly tested on normal function exits.
- ridiculous_fish 3y agoRust does have manually-written error handling paths like that. See for example the panic handling in Vec.retain_mut: https://doc.rust-lang.org/src/alloc/vec/mod.rs.html#1577 https://doc.rust-lang.org/src/alloc/vec/mod.rs.html#1577 I doubt most crates handle these scenarios correctly.
- pornel 3y agoThis is limited to unsafe code, and the "exception safety" is a known problem to deal with. It can be tested without having to trigger OOM.
- lumb63 3y agoIMO (systems programming background), the litmus test for panic! vs. Result doesn’t exist. Don’t panic.
- KRAKRISMOTT 3y agoIf you are building application software like a web framework, panicking and then dealing with the issue using a global exception handler to return 500 is often the easiest. There was no point in littering the code with match Result => err return http.status500 like bad Go.
- kaba0 3y ago(That would be the point of exceptions that make the correct thing the majority of times, and why I think they are superior, checked exceptions that it. They are completely analogous to Result types, but are properly supported by the language and can have as small or big scope as needed. I am really hopeful that they will have a resurrection with languages with effects)
- dangerlibrary 3y agoThis is sometimes called the diaper (anti)pattern - because it catches all the poop. It works great - so long as the only exceptions your program ever throws are ones you are deliberately throwing to the global error handler. Given that, go for it. ;)
- jstimpfle 3y agoAs an outsider, is panic() like assert()?
- PuercoPop 3y agoIt is like printf to stderr and exit(1)
- bluejekyll 3y agoassertions often get turned off in production/release code, panics do not.
- jdmichal 3y ago> The litmus test for panic! vs. Result<T,E> is not rarity of occurrence, it's whether the condition represents a programming bug or a recoverable error. Because that exact same conceptual separation worked so well for Java with checked vs unchecked exceptions... Everyone just started using unchecked exceptions because they provide an easier coding experience. Also, there's legitimate situations where the library cannot make that decision, but rather the user. As someone else says in another example, who are you to say that my request to allocate too much memory is a panicable offense? What if my program can, in fact, recover from that situation? At least in Java, catching checked vs unchecked exceptions is the same if you do choose to handle them.
- lumost 3y agoaye - in Java, this inevitably leads to strange catch Exception/RuntimeException statements all over the code. In practice, there are very few/no reasons to order a program crash. Programming errors are inevitable on a large code base, we learned the hardway in kernel development that Blue Screen Of Death is not the correct outcome for an error.
- dap 3y ago> > The litmus test for panic! vs. Result<T,E> is not rarity of occurrence, it's whether the condition represents a programming bug or a recoverable error. > Because that exact same conceptual separation worked so well for Java with checked vs unchecked exceptions... > Everyone just started using unchecked exceptions because they provide an easier coding experience. Indeed. That's a problem with exceptions and checked exceptions and the choices in Java around that, not the idea that operational and programming errors might be handled differently. > Also, there's legitimate situations where the library cannot make that decision, but rather the user. What you're describing is that different components may choose to treat these separately. That's fine -- there doesn't need to be an objective answer. You can have one library say "allocating too much memory is not an error we care to deal with and we treat that as a programmer error". And people using that can be told that's a limitation. That's fine. All components have limitations. Another library that implements the same thing can say "we treat allocating too much memory as a recoverable operational error and express it in this way". It's all tradeoffs. That also doesn't mean _all_ such cases are subjective. Another comment mentioned an index out of bounds in quicksort. That's completely within the control of the implementation and in most contexts there's no reason that should ever be a recoverable error.