The author appears to be trying to use error messages in their own code to debug it which is a pretty weird way to use error messages. Error messages are for humans and users. If you are developing your own code you can just use a debugger to debug the problem. Assuming they only had access to basic tools they could have just plopped down a breakpoint in the relevant error return from copy_from_process() and slowly w…
Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
81–90 of 204 posts
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#82I recently tweaked my application's failure reporting [3] to go from this embarrassing thing:
E0211 073750.559 main moonfire_nvr] Sys(EROFS)
to the more useful: E0211 111025.109 main moonfire_nvr] Exiting due to error: Failed to open dir /home/slamb/mymount/sample
caused by: Unable to open meta file
caused by: EROFS: Read-only file system
(set environment variable RUST_BACKTRACE=1 to see backtraces)
I should have thought long ago to advertise setting RUST_BACKTRACE=1 right in the error message, but better late than never.[1] https://crates.io/crates/failure
[2] https://github.com/rust-lang/rust/pull/72981#issuecomment-72...
[3] https://github.com/scottlamb/moonfire-nvr/commit/9a5957d5efa...
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#83Earlier quoted context omitted.
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 biggest problem with that is that it is very unwieldly if you're using any kind of higher-order functions. To fix that, you need to start supporting error polymorphism. For example, `map` should have a signature like map :: List a -> (a -> b -[err]) -> List b -[err] So that map [1 2 3] +1 //no errors map [1 2 3] sendOnNetwork //returns NetworkError At least, this is one of the major limitation of Java's Checked E…
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#84Error 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…
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#85Earlier quoted context omitted.
The only system I think should completely go is Exceptions except in the case of termination or absolutely catastrophic failure - this isn't really about programming but rather that the implementation is a total pain, the compiler struggles to optimize them, and even better they make quite a few safety analyses like borrow checking very difficult because the control flow graph basically explodes when you start consid…
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…
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#86Error 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…
> 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 to track down later).
The main weakness of this system, imo, is that the thrower, not the caller, decides whether or not a given error must be handled, and sometimes the answer is "it depends on what the consumer is doing".
That said, the powerful (mainly, no-implicit-null...) type systems that are starting to become prevalent prevent a lot of cases that would have been errors 20 years ago from existing in the first place. In modern typed languages an error is almost always a genuine IO/environment anomaly, which means there are a lot fewer of them to handle in the first place.
Edit: The other big weakness of Rust's system, as mentioned in the article, is the jumble of all the different disjoint Error types. I think the core issue here is that Rust doesn't have ad-hoc union types. I.e. if you want to say "this value is of type X or Y or Z", you have to declare a new enum somewhere, and embed your possible types in each branch, and that's a lot of ceremony at each point where you bubble up a different possible type of error. I understand why Rust's enums are static, though, I wonder if there's a place for some sort of heap-allocated ("dyn?") solution that allows any combination of possible types.
Edit 2: Actually this probably wouldn't be possible because there would be no way to distinguish the union, because Rust carries no type info at runtime. Maybe there could be syntax sugar for anonymous enum types declared inline?
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#87Error 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…
> Error handling has been wrong since the beginning 100% this. The very concept of "error" is philosophically unsound. There are no errors; only conditions that you dislike. It is unfortunate that programming languages allow to express your emotional detachment to one of both cases of a branch. Nothing good can come from that. I yearn for a language with no error handling nor exceptions. Just plain language construct…
This is true in mathematical sense, but unhelpful in UX sense.
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#88Earlier quoted context omitted.
for exploratory coding you can also just unwrap, assert, panic.. It's useful to remember that error handling is optional in those cases :)
anyhow with ? is even shorter than unwrap. If it’s likely to have error at some point, I’d throw in a .context, it is so convenient. Edit: typo.
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#89Earlier 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.
For some domains, you can write a specification that has value in itself, it will be shorter and easier to review.
For other domains, the program itself is the best specification for the desired behavior. There is nothing special about a specification that makes it inherently more correct than a program. The specification may be large enough and detailed enough that it is essentially just as hard to review as the program output. The specification can have subtle bugs, just like a program. Even worse, the specification itself is harder to test, especially for corner cases.
It can be very easy to produce an excellent specification that solves a different problem than expected, especially for complex problems with many moving parts and many possible use-cases.
Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)
#90Error 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…