3 ms·
Well, you handle errors by needing to explicitly handle them at the point of error, as opposed to all callers needing to anticipate and understand every random
by presentation 2y ago
Well, you handle errors by needing to explicitly handle them at the point of error, as opposed to all callers needing to anticipate and understand every random system error from 10 levels deep of APIs (or just throw them all away).
- XorNot 2y agoExcept this isn't my experience of errors at all. My experience of errors is that most of the time you need more scope in order to handle them properly. I.e. if writing to a file happens, what am I actually supposed to do about that? Well, that depends entirely on why I'm writing to a file. Which might not be information the calling function actually has. Usually I need to go up the call stack to find somewhere which has enough context to know what's actually not working because a file write has failed. Basically, the vast majority of my code can always error or depends on things which can: or is one refactor away from now needing to return errors. If just about everything is Result<T>, then really why should anything be? Why eat the syntactic noise?
- Mawr 2y agoOf course you think the majority of your code can error - exceptions don't let you draw a distinction between fallible and infallible code, so you have to assume all code can fail. This leads to two problems: 1. You can't take advantage of infallible code... Infallible code is much easier to use because there is no need to worry about errors. But you can't take advantage of that because infallibility is not encoded in any way. With Result types, infallible code is clearly marked, which allows for sectioning it off from fallible code. Programmers naturally gravitate towards doing just that because they want to take advantage of the ease of use. The result is a lot of pure functions and as little fallible code as possible. 2. ...but you will erroneously try to do so anyway You will inevitably start assuming that certain code can't possibly fail. The ease of use of infallible code is just too alluring: [1] [2] [3]. [1]: https://nedbatchelder.com//blog/202001/bug_915_solved.html https://nedbatchelder.com//blog/202001/bug_915_solved.html [2]: https://devblogs.microsoft.com/oldnewthing/20050114-00/?p=36693 https://devblogs.microsoft.com/oldnewthing/20050114-00/?p=36... [3]: (a little wordy) https://www.joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong/ https://www.joelonsoftware.com/2005/05/11/making-wrong-code-...
- XorNot 2y agoI don't care about code which "can't error", because it can't error. The only code I care about is code which can error, or worse, code which is expanding due to a requirements change and is about to make the transition to "needs to be able to return errors". There are vanishingly few business logic processes that can't error, because every bit of disk IO, network IO and user input can always throw an error that needs to be handled. What I am saying is that the benefits of pure functions are obvious, but the number of practical applications of them is far smaller then their advocates claim. They don't save me from the fact that the network may be down, the target device might crash, someone might knock the power out at the other end, or the network card picks that moment to corrupt a packet. What is the point of spending a lot of syntax on Result<T> types returning all over the place, rather then just throwing a try-except around the places in my code I know I can reasonably bound and define what the recovery process is if an error does occur. Which for every non-toy example, is a guarantee.
- erik_seaberg 2y agoInfallible code is too rare to be worth any effort. Even math can fail (though most platforms are stuck with legacy decisions to quietly return wrong answers). And you always have to recover from a timeout due to a downstream failure in some of the cheap commodity hardware that's running your code.
- brabel 2y agoI tend to agree with you. Rust uses Result types and for any real-world API, you can be almost certain that 90% of operations can fail and need to return Result. You can see that in most Rust code that's not just algorithms, you will have a `?` at the end of nearly every method (which is the way Rust propagates errors, similar to how Exceptions are automatically propagated in most languages - but they don't require the `?` to mark them). Rust kind of cheated a bit with arithmetic and it doesn't return a Result when you use division, for example (it's cheating because if not for convenience, it really should return Result as arithmetic errors like division by zero and reaching a NaN are fairly common - and hence would justify that).