Error handling has been wrong since the beginning, and has continued to be wrong ever since. First, we had error codes. Except these were wrong because people forget all the time to check them. Then we had exceptions, which solved the problem of people forgetting to check by crashing the app. Then the Java team got the bright idea to have checked exceptions, which at first helped to mitigate crashes from uncaught exc…
Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
91–100 of 204 posts
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#92Earlier quoted context omitted.
Code is primarily meant to be read by humans. Humans can't focus on 30 things at once when reading code. A function that should take a list of strings and return a list of all the strings in the first list starting with 'A' will be harder to read if it must also handle allocation errors for the new list, because they are a completely different kind of concern. Even outside of programming, human thought often works ex…
> I am designing my program for a particular use, by definition. No; this is bad engineering. You write a program to conform to a specification. In the specification, it says what must happen when a file does not exist, what must happen when there's not enough memory, etc. Then you write the specified behavior into code.
I've never, ever seen a specification which mentions file-not-found or out-of-memory errors. The "specifications" I get from my clients are more like (paraphrased):
> Listen, adwn, I have all those files in a shitty, undocumented file format designed by another group in another building, could you please add an import button for them? Oh, and can I have it by Friday? Thanks, you're the best!
I'm exaggerating only slightly. And then I go and try to make sense of what they need, and I implement error handling on top of it.
Your specifications tell you exactly how to deal with file-not-found situations? You lucky bastard ;-)
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#93Earlier quoted context omitted.
In terms of control flow, this: try { someCall(); } catch (ErrorICanHandle err) { //handle } perfectly equivalent to this: err = someCall(); if canHandle(err) { //do something } else { return err } I don't see why so many people think exceptions make code harder to analyze. In my opinion, it is errors themselves that make code hard to analyze, regardless of implementation strategy. The only difference between excepti…
Exceptions make code harder to analyze because they implement non-local control flow. Your two example statements aren't really equivalent. `ErrorICanHandle` may be a kind of exception that the `someCall` function has no idea about whatsoever -- it could be an exception propagated from much farther down the call stack -- while your if statement assumes the error was explicitly returned from the function.
someCall()
is equivalent to code in a language without exceptions that looks like this: err = someCall()
if err {
return err
}
(ignoring for a moment non-error returns, which don't change the point significantly)Having functions that are guaranteed not to throw / return errors doesn't significantly change this shape.
So basically it's no more non-local than the code you'll end up writing with error codes, in most cases, any way. The only difference is implicit vs explicit.
> `ErrorICanHandle` may be a kind of exception that the `someCall` function has no idea about whatsoever -- it could be an exception propagated from much farther down the call stack -- while your if statement assumes the error was explicitly returned from the function.
someCall doesn't need to know about the meaning of the error in either case. It only needs to propagate any error it receives from any functions it calls (that it can't handle itself). Think about the function I wrote myself: did it need to know the precise type of err? Nope - it just needed to know that it implements some kind of Error interface (which may be as simple as being a negative number, like a POSIX error code).
Edit to give a more complete example:
extern void bar();
void foo() {
bar()
doOtherStuff()
}
void someCall() {
foo()
doMoreStuff()
}
void main() {
try {
someCall()
doFinalStuff()
} catch (BarSpecificException e) {
doErrorStuff()
}
}
Is equivalent to this code: extern err bar()
err foo() {
err = bar()
if err {
return err
}
err = doOtherStuff()
if err {
return err
}
}
void someCall() {
err = foo()
if err {
return err
}
err = doMoreStuff()
if err {
return err
}
}
err main() {
err = someCall()
if err is BarSpecificException {
err = doErrorStuff()
if err {
return err
}
} else if err {
return err
}
err = doFinalStuff()
if err is BarSpecificException {
err = doErrorStuff()
if err {
return err
}
} else if err {
return err
}
}
If I ask you in the second piece of code what will be executed after the call to foo(), is it any easier to reply than in the first version? Personally, I don't believe so.Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#94Earlier quoted context omitted.
Are you familiar with Zig's error handling? Except for the fact that errors cannot contain payloads, it is, imo, perfect.
it has the same issues. You can always discard errors with `catch unreachable` for example.
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#95Error handling has been wrong since the beginning, and has continued to be wrong ever since. First, we had error codes. Except these were wrong because people forget all the time to check them. Then we had exceptions, which solved the problem of people forgetting to check by crashing the app. Then the Java team got the bright idea to have checked exceptions, which at first helped to mitigate crashes from uncaught exc…
And I'm no Rust developer, but it looks to me like it basically demonstrates how Rust is an abject failure in that regard. The developer has to jump through lots of nonobvious hoops and choose between competing libraries to get anything useful.
Contrast that with Java, where any uncaught or logged exception prints a detailed stack trace and (usually) one or more useful error messages, by default, since day one.
This is a problem with very good known solutions, yet Rust seems to fail hard.
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#96Error handling has been wrong since the beginning, and has continued to be wrong ever since. First, we had error codes. Except these were wrong because people forget all the time to check them. Then we had exceptions, which solved the problem of people forgetting to check by crashing the app. Then the Java team got the bright idea to have checked exceptions, which at first helped to mitigate crashes from uncaught exc…
It's not perfect, but I think Rust's approach is the best one yet. > Any error system that handles all errors the same way will fail because there are some errors we can ignore, and some errors we must not ignore. Rust has separate categories for these two things. Panics cannot be handled , which pushes the author to use them sparingly. Results must be handled (or explicitly elevated to panics, in a way that's easy t…
So... exactly the same problem that Java's checked exceptions have?
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#97as someone who works 95% of the time in rust, how to handle my errors is never a problem for me. I think the issue is the expectations of people coming into it with a different frame of reference, expecting the kind of traceback/exception framework built in - and for that to be a typical debugging workflow. like 95 times out of 100, I just `.map_err(|e| /* code to convert e to return type's error... */)` and I'm done…
Rust also has the traceback/exception error handling mode in the panic cases. And since there's no standard way to check those at compile time you're left to fuzz the code to find all the possibilities (or use some hacks). It would be great if the compiler could be put into a mode where panics are handled like errors that need to be explicitly handled. Maybe something like: 1) At the function level or crate level bei…
This also looks interesting: https://github.com/Technolution/rustig
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#98Error handling has been wrong since the beginning, and has continued to be wrong ever since. First, we had error codes. Except these were wrong because people forget all the time to check them. Then we had exceptions, which solved the problem of people forgetting to check by crashing the app. Then the Java team got the bright idea to have checked exceptions, which at first helped to mitigate crashes from uncaught exc…
It's not perfect, but I think Rust's approach is the best one yet. > Any error system that handles all errors the same way will fail because there are some errors we can ignore, and some errors we must not ignore. Rust has separate categories for these two things. Panics cannot be handled , which pushes the author to use them sparingly. Results must be handled (or explicitly elevated to panics, in a way that's easy t…
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#99Earlier quoted context omitted.
It's not perfect, but I think Rust's approach is the best one yet. > Any error system that handles all errors the same way will fail because there are some errors we can ignore, and some errors we must not ignore. Rust has separate categories for these two things. Panics cannot be handled , which pushes the author to use them sparingly. Results must be handled (or explicitly elevated to panics, in a way that's easy t…
One of the biggest issue with Rust’s panics is there’s many times when you must never panic. For example in an OS, when trying to save your crucial data to disk, in real-time code where panicking would maybe kill someone in the real world, etc
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#100Error handling has been wrong since the beginning, and has continued to be wrong ever since. First, we had error codes. Except these were wrong because people forget all the time to check them. Then we had exceptions, which solved the problem of people forgetting to check by crashing the app. Then the Java team got the bright idea to have checked exceptions, which at first helped to mitigate crashes from uncaught exc…
I think that exceptions are a problem and cause this developer burden only because they are invisible. If they appeared in the type signature, for example as () -[DatabaseReadError]-> () then they would be part of a function's 'contract'. With this, consumers of your function are making an active decision about whether to handle or bubble an exception without examining your implementation, and the type of the main fu…
The problem is that it makes the most common case (letting the exception bubble up) very inconvenient and clutter-y. Signatures with 5 different declared exceptions are worse than useless.