Live data from Hacker News

Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

msirringhaus.github.io

61–70 of 204 posts

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#61

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…

> Then we got multi-return error objects, maybes, panics [...] that fail to understand the basic premises of errors:

> Any error system that relies upon developer discipline will fail because errors will be missed.

> 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.

Not sure how that's true for Rust. Functions that can fail, return a Result, that contains either a value or an error. If you want to use the value, you have to either explicitly check which one is it (you can handle or ignore the error at this point), or quickly access it by unwrapping the Result, which will crash (panic) the program on error.

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#62

Earlier quoted context omitted.

> 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…

Well, what you're saying is exactly the reason why java called them Exceptions and not Errors (well, Error also exists, but it is generally reserved for very nasty problems). Anyway, you can't just define the problem away, or else you end up with Go style error handling - that is exactly what a language with no built-in support for errors looks like. Languages need to offer control flow mechanisms that allow you to s…

> Languages need to offer control flow mechanisms that allow you to separate common cases in the code from the uncommon cases.

Strong disagree with this sentence. It represents the exact opposite of what I deem a good programming language. The difference between "common" and "uncommon" execution paths must be of no bearing. Moreover, this "likeliness" depends on the (unknown to the programmer) usage that the program will be put through. For all you know, the uncommon path may be the only one that will be ever traversed in all instances of your program. A correctly specified program must deal with all possible input conditions, and that includes missing files, inconsistent parameters, and lack of resources. A filename existing or not is the same boolean value as an integer being even or odd.

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#63

Earlier quoted context omitted.

Well, what you're saying is exactly the reason why java called them Exceptions and not Errors (well, Error also exists, but it is generally reserved for very nasty problems). Anyway, you can't just define the problem away, or else you end up with Go style error handling - that is exactly what a language with no built-in support for errors looks like. Languages need to offer control flow mechanisms that allow you to s…

> Languages need to offer control flow mechanisms that allow you to separate common cases in the code from the uncommon cases. Strong disagree with this sentence. It represents the exact opposite of what I deem a good programming language. The difference between "common" and "uncommon" execution paths must be of no bearing. Moreover, this "likeliness" depends on the (unknown to the programmer) usage that the program…

> The difference between "common" and "uncommon" execution paths must be of no bearing.

Why? I think that a good programming language should help readers focus on the "essence" of an algorithm. Usually, handling stuff like memory allocation errors is just noise in that effort.

Besides, most errors will usually be propagated to the caller, so I think the programming language should make that convenient, like Rust does with its ? syntax, and most languages do (perhaps too implicitly) with some concept of exceptions.

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#64
post #10

Earlier quoted context omitted.

Completely agree. I used to create my own error type(s) manually and implement the various conversions for 3rd party crates and it was quite a lot of boilerplate but with anyhow (for applications where you don't really care about strict error types) and thiserror (when you need to be a little more thorough). Actually that's effectively TFA's solution, if they had used thiserror/anyhow from the start there might not h…

This is really interesting because I recently found the anyhow crate and I was wondering why it's not mentioned anywhere else. Definitely feels like useful information that a newly minted Rust dev could make use of.

Indeed. I wish I learned about it earlier myself, it would've saved me some boilerplate in the past.

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#65

Earlier quoted context omitted.

Well, what you're saying is exactly the reason why java called them Exceptions and not Errors (well, Error also exists, but it is generally reserved for very nasty problems). Anyway, you can't just define the problem away, or else you end up with Go style error handling - that is exactly what a language with no built-in support for errors looks like. Languages need to offer control flow mechanisms that allow you to s…

> Languages need to offer control flow mechanisms that allow you to separate common cases in the code from the uncommon cases. Strong disagree with this sentence. It represents the exact opposite of what I deem a good programming language. The difference between "common" and "uncommon" execution paths must be of no bearing. Moreover, this "likeliness" depends on the (unknown to the programmer) usage that the program…

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 exactly in terms of general cases and exceptions. It's just what comes naturally, and we shouldn't be fighting it in code.

> The difference between "common" and "uncommon" execution paths must be of no bearing. Moreover, this "likeliness" depends on the (unknown to the programmer) usage that the program will be put through. For all you know, the uncommon path may be the only one that will be ever traversed in all instances of your program.

As the designer of that program, I obviously know up to a very good degree of confidence what the usage of the program will be: I am designing my program for a particular use, by definition. Sure, I may not know exactly how flaky your network may be, but I know that this program only really works on networks that deliver more packets than they drop, that can read all of the bytes I wrote to disk back, at least most of the time, and so on.

Or, perhaps I'm writing a program that is meant to run on very flaky networks (say, a device for wireless thunderstorm sensors): I expect that program to look very different from the Netflix app's networking code.

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#66

Earlier quoted context omitted.

> Languages need to offer control flow mechanisms that allow you to separate common cases in the code from the uncommon cases. Strong disagree with this sentence. It represents the exact opposite of what I deem a good programming language. The difference between "common" and "uncommon" execution paths must be of no bearing. Moreover, this "likeliness" depends on the (unknown to the programmer) usage that the program…

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.

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#67

Earlier quoted context omitted.

Well, what you're saying is exactly the reason why java called them Exceptions and not Errors (well, Error also exists, but it is generally reserved for very nasty problems). Anyway, you can't just define the problem away, or else you end up with Go style error handling - that is exactly what a language with no built-in support for errors looks like. Languages need to offer control flow mechanisms that allow you to s…

> Languages need to offer control flow mechanisms that allow you to separate common cases in the code from the uncommon cases. Strong disagree with this sentence. It represents the exact opposite of what I deem a good programming language. The difference between "common" and "uncommon" execution paths must be of no bearing. Moreover, this "likeliness" depends on the (unknown to the programmer) usage that the program…

Strongly disagree with your disagreement. Programming features help you organize your code. The fact that you actually have a robust software or not with what the language offers is another problem.

When people say "errors are values", I say: yes, but they are a special kind of values. The same way floats are special (signaling NaNs), or that bools are special (short-circuit operators). It is great to have special support for values which need to be used in a certain way (here: don't lose any error, bubble up by default).

It is great to have the opportunity (not the obligation) to use features for separation of concerns. This makes it a bit like an aspect-oriented approach where normal code emits errors and error handling code elsewhere knows how to handle/restart them. If you language allows it, it makes also sense also to decouple logging (tracing functions) or data-access permissions (postgresql row level security).

In the C code I maintain at work, everything is here in plain view, logging, error handling, etc., and I am not complaining, but more recently we tend to use other languages or code generation a lot (think of something like protobuf) because it makes code a lot easier to maintain.

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#68

Earlier 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.

The specification and boundary conditions directly comes from an analysis of the expected usage. Except for some all-purpose libraries you don't develop in a vacuum (assuming you don't work for Roomba).

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#69

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…

> 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…

Maybe CL got this right with the condition/restart system? In addition to their utility for experimental programming, conditions work really well for handling errors programatically.

The general problem seems to be something weird happening far down in the system, for which the correct way forward is dependent on how we got there. This situation can't be handled where the issue happened since that would break encapsulation, but unrolling the stack all the way up blows away the context that is necessary to understand how to move forward. I don't see how a system that either unwinds the stacks (throwing errors) or tries to encapsulate the state through the system (Either) would truly solve the issue.

Re: Where Everything Went Wrong: Error Handling and Error Messages in Rust (2020)

#70

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…

Are you familiar with Zig's error handling? Except for the fact that errors cannot contain payloads, it is, imo, perfect.
Post reply on HN