7 ms·
I very strongly believe exceptions are a lot closer to optimal than Result is. Exceptions remove the need for inline error checking code and make it possible to
by quotemstr 10y ago
I very strongly believe exceptions are a lot closer to optimal than Result is. Exceptions remove the need for inline error checking code and make it possible to implement types with value semantics. You can't have reasonable value types that own resources if you need explicit error checking.
The need for explicit error checking makes OOM handling in Rust awkward at best. I've ranted about this side effect before.
Also, in Rust since we can panic, we need to worry about exception anyway! Rust has the worst of both kinds of error handling.
Exceptions are anti verbosity: you're supposed to let them propagate, not catch and rethrow them. They don't erase context: they preserve it, since an exception object is constructed as close as possible to the error site that caused it.
I realize that I have a minority view, but I'm utterly convinced that I'm right and that I'm living in a world gone mad. I've written a ton of code over the years. At least hear me out and try to understand my perspective.
- tupshin 10y agoPersonally I love Rust's error handling, but I do think that I understand your perspective. At least part of your objections would seem to be addressed by the combination of the ? operator to make it trivial to do the equivalent of re-throwing inline, and the error-chain crate, which can make exception-like stack traces/etc trivial to implement. https://brson.github.io/error-chain/error_chain/index.html https://brson.github.io/error-chain/error_chain/index.html
- zubat 10y agoI think I know what this trend is, more generally. It has to do with how explicit our code is. We've been through an era where you have some very powerful and compact indirection constructs(event callbacks, polymorphic objects, dynamic types, exceptions) in common parlance and the trend has turned against these lately. Their utility in many instances is mostly to enable technical debt, by worrying about the edge case later, and this has scared a generation of coders who have seen it go astray too often and create code that is hard to usefully refactor. And while exceptions aren't at the center of that trend, they're often implicated as a contributor. With the new trend, you pay up front and go verbose, put more logic at the call site instead of indirecting it away. Go is at the leading edge of that: lots of LOC for boilerplate is OK in Go-land. I'm more pragmatic with my error handing methods: I mostly care about whether I can eliminate a class of errors altogether, and secondarily what debugging implications are presented. I don't have a strong opinion on verbosity although I have followed the trend in that respect towards more call site logic.
- quotemstr 10y agoThis trend represents the unlearning of very hard earned lessons. Personally, I can't wait until people rediscover that programming can be more fun and productive without boilerplate. A language being explicit, by itself, is not a feature. Being explicit instead of implicit is only worthwhile if you get clarity in exchange, and boilerplate is clarity-reducing because it's so regular and so obscures program logic.
- burntsushi 10y agoIn Rust, in the common case, the boiler plate you're talking about here is literally a single sigil. (Previously, it was `try!(...)`.) This is of course to say nothing about the advantages of having something that signals "this operation can return an error," (at the call site) but you seem to dismiss that out-of-hand.
- quotemstr 10y agoI do dismiss this advantage out of hand: almost everything can fail, because most things allocate memory. It's only because Rust treats memory specially (incorrectly --- memory is just another resource) that it doesn't appear that more functions can fail. It's much more valuable to flip the sense of the annotation and mark the few functions that cannot fail in any way. Allowing most code to throw just reflects reality and allows you to stop obscuring your program logic with mechanical error handling plumbing. All you do with "try!" is annoy readers by constantly reminding them that things can go wrong when the default assumption should be that things can go wrong.
- burntsushi 10y ago> It's only because Rust treats memory specially (incorrectly --- memory is just another resource) Which is a perfectly reasonable trade off to make. Of course, it's not always the right trade off, so we're looking to improve our story there. If you can't acknowledge that there are real trade offs at play here, then I don't really see how it's possible to meaningfully understand your position (or have a non-frustrating conversation).
- dragonwriter 10y ago> You can't have reasonable value types that own resources if you need explicit error checking. The proper place for the period in that sentence is before the "if"; owning resources is not a reasonable thing for a value type to do.
- quotemstr 10y agoTell me more about how std::string is unreasonable.
- steveklabnik 10y agoAre you talking about Rust's or C++'s? Name conflict :) In Rust, std::string::String is not a "value type", and by that, I mean it's not Copy.
- quotemstr 10y agoC++'s.
- steveklabnik 10y agoThen I won't comment, though I wonder if the parent is thinking of things like https://groups.google.com/a/chromium.org/forum/#!msg/chromium-dev/EUqoIz2iFU4/kPZ5ZK0K3gEJ https://groups.google.com/a/chromium.org/forum/#!msg/chromiu...
- computerphage 10y agoI think people would be more inclined to try to understand your perspective if you hadn't called Rust's design "jumping on the bandwagon", which, to me, implies a thoughtless act of conformity rather than a deliberate trade-off towards explicitness. To me, verbosity is bad, but implicitness is worse. I like the trade-off that ? (the question mark operator) has stuck for Rust. I agree that OOM handling in Rust should be improved. I don't agree with the way you talk about panics. They aren't just exceptions by another name because they're not intended to be used for handling expected errors (like exceptions are). Instead, they terminate the program. That's like attacking Java's System.exit() for not being just another exception. Many other environments share this distinction between fatal and recoverable errors. It can sometimes be a difficult choice to choose what to use, but having panics doesn't mean that all code must somehow try to handle them.
- quotemstr 10y agoPanics are recoverable: initially at task boundaries, and these days at catch points. They are literally exceptions and unwind the same way. The designers intended for programs as a whole to keep running after a task panics. Code running in such a context needs to avoid leaking and corrupting resources on unwind --- i.e., be exception safe. On the rust development list, people call this property literally "exception safety". I really do think that Rust error design avoided exceptions without properly considering the advantages of the exception model and the inevitably of turning panics into a full exception mechanism.
- computerphage 10y agoI don't agree that panics are exactly equivalent to exceptions in languages like Java or Python because the language doesn't support using them as a general purpose error handling technique by providing `try/catch/finally` or by documenting what exceptions may be thrown with `throws`. I agree that the implementation of unwinding is similar in both cases, but I'd argue that that's not sufficient in practice to be able to apply knowledge about the usage of exceptions in, say, Java to the usage of panics in Rust. I'm aware of catch-panic and the unwinding related to panics. Nevertheless, the vast majority of panic usage I've seen is related to the semantic that a panic signals an error that is fatal to the context of the panic. (This is a more nuanced view of panics that didn't exist in my previous post.) Yes, you can use catch-panic on a server that is meant to stay up even if one of its threads panics. Or you can replace unwinding with aborting to save on code size. But idiomatic Rust code doesn't use panics simply to signal to a caller that some sort of typical error occurred like a file not existing. Edit: I realize that my post may come across as arguing over semantics. I really don't care whether they're called exceptions or panics or even if they're mechanically the same thing. What I'm trying to talk about is whether they cause code to become harder to understand because of implicit error cases that are invisible in the source. 2nd edit: I appreciate your several good points in your replies to my posts.