Live data from Hacker News

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

msirringhaus.github.io

161–170 of 204 posts

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

#161

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…

[deleted]

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

#162
post #42

For the mostpart, Rust error handling is okay. What really rustles my jimmies, however, is the often mandatory indentation because of a lack of an inverse "if let". I prefer to bail out of a block if a condition is NOT met, rather than execute another nested block if it IS met. Rust makes that harder than it should be. It's good code hygiene in every other language, and Rust makes it painful in places. I've even been…

I'm confused, have you found the try operator ("?") insufficient for your use cases? I believe it does what you are describing, ex: fn process_file(p: Path) -> Result { let file = File::open(p)?; //Return err if file can't be opened let mut out = String::new(); file.read_to_string(&mut out)?; // Return err if read fails out } If you want to handle the error case within the same function `try` blocks are available in…

`?` only helps if the thing you want to do on Err is return from the whole function. You can't use it for finer-grained break / continue / exit-from-current-block (until `try` blocks are stabilized).

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

#163

Earlier quoted context omitted.

To be fair, throw is GOTO. Catch() is COMEFROM :).

Ah, my peeps! I love you guys. enriquto when you talk about "a language with no error handling nor exceptions" it reminds me of a crazy idea i was toying with: what if you made all "exceptions" require handlers, e.g. what if every divide had to be accompanied by code to deal with divide-by-zero? In other words, DIV(X, Y, Foo) would be (X/Y if Y != 0 else Foo()) And so on...

that's the way some embedded control systems are designed. with some (many) errors (can't read/write) being fatal and shutting down the system after an alarm is sent.

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

#164

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…

I feel like error handling is fine in like C#. No checked exceptions, and stack traces come with the exceptions, and you can nest them. What's not to like?

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

#165
post #13

I find this article hard to read. But I believe its point stands. In Rust: - You bubble up errors using `?` operator, - then you get a nice error message. - However the location of the error is lost, the more complex the program, the harder it is to figure out where "permission denied" for example comes from.

The whole article was basically the author figuring out how to get a full path error message instead of only getting the first or last component of the error path. Also, how to do it without also crashing the program entirely. Plus of course getting some context about the state of the program when it crashed, and without imposing the full stack trace overhead since this error was supposed to be available even on production builds.

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

#166

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…

Well, no, there are errors, and then there are environmental situations (if we ignore, for a minute, hardware malfunctions).

like "file not found", "disk full". Something in between like "out of memory".

Misusing an object as the wrong type, or division by zero, or accessing missing memory are errors. These usually point to defects in the program, or in some cases defects in the program's defense against bad inputs.

There are related errors are the hardware level, like numeric exceptions and bus errors. Without these, machine-language programs just lock up or produce garbage results.

Situations like "file not found" or "host not reachable" are usually environmental conditions, and not internal problems. There are ways in which they can be internal problems; two modules in a program might be related in such a way that one prepares a file that the other expects to exist, and there can be some bug in that.

Then there are situations like "out of memory" or "disk full" are somewhere in between. All the operands to the calculation exist and are well-defined, the operation is correct, but just there is a resource issue. In pure computing theory, these situations are the heart of the distinction between simulating a Turing machine by means of a finite tape, and the Turing machine abstraction, as such, which has unlimited tape.

In summary, there are basically three categories: errors (programming mistakes), environmental situations (issues in presentation of the inputs to the program, like asking it to operate on a file that doesn't exist, or connect to a host that is down) and resource exhaustions (out of some type of storage).

There is no emotional attachment in this classification whatsoever; and there is value in their separation.

Then there is another category of errors: faults in the hardware. The foregoing assumes that there are no malfunctions in the hardware; no cosmic rays that collide with silicon, flipping the values of bits and such. In some situations, you need a demonstrated strategy for these. Like what if an error happens in a DRAM chip that is not detected and corrected.

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

#167
post #83

Earlier quoted context omitted.

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…

And if the function can throw different kinds of exceptions, you need a way to express the union of unrelated exceptions (without defining a new variant type), a bit like Polymorphic Variants I guess.

Ideally also a way of saying "... except for X Y Z" while remaining appropriately polymorphic. I've remarked before that while checked exceptions help make sure you consider every possible situation, imprecision forces you to consider many (too many?) impossible situations as well.

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

#168

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.

You're forgetting about errors that happen due to programming mistakes.

I've never seen an end-user application accompanied by a written a specification about what happens if there is a run-time error due to a mistake in the program.

Your original thesis is something like that "there are not errors, only conditions we care about"; but then this subsequent argument is disappointingly about environmental conditions only.

If I have a program that takes two run-time inputs and divides them, I may or may not specify what happens if the denominator is zero. I could explicitly specify that the behavior is not defined; my program can do anything. (In practice, any decent processor will catch it via some numeric exception.)

If my program generates a division by zero due to a programming bug, where no such division is implied by the specification of what the program does on the inputs which it is given, that's something we don't bother specifying. Not usually.

Anything can happen if the program has a mistake. A document listing all possible mistakes and how the program will react will not only be intractably long, but in the course of writing it, you would just inspect that the program doesn't have those mistakes. In the end, you'd be left with a document describing mistakes that the program doesn't actually contain, while it remains vulnerable to unknown mistakes.

We might be required to have a strategy for the software to deal with its own faults in a general way, if we are working on something safety-critical. Such as that no matter how the program might fail, the system as a whole will revert to a safe state.

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

#169

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…

I feel like error handling is fine in like C#. No checked exceptions, and stack traces come with the exceptions, and you can nest them. What's not to like?

IMO exceptions are a terrible way to signal errors. They obscure control flow and make it much harder to reason about a program's behavior. They make it easy to forget to check for errors, and encourage sloppy catch-all error handling. It is a lot harder to determine if exception-based code is correct or not, and languages that have exceptions require you to examine literally every line of code to determine if it can throw.

Even the name is wrong: an "exception" should signal truly exceptional behavior, things that you would not expect to happen unless something is really wrong. And yet exceptions are thrown for mundane things like "file not found", something you could very easily expect to happen routinely.

Exceptions should be like Rust's `panic!()`: only for things that the programmer can't reasonably do anything about, which will cause the program to terminate.

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

#170
post #126

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…

> Any error system that relies upon developer discipline will fail because errors will be missed. Haven't there been some languages that force functions to return some kind of tuple like: result,error And forces the programmer to at least do: if(error) { } It does not force any kind of correct handling, but simply oversights should be caught. I might be imagining things though.

There's no "forcing" there. You can simply ignore the error part of the tuple, or even just forget to check it.

If the function returns a (non-error) value that is directly accessible from the function call, the programmer is not forced to do anything with the error.

This is exactly the same problem with null: forget a null check, and you're hosed. Forget an error check, and you're hosed.

If you make errors a part of the actual single return type (as Rust does), then you have to explicitly deal with the possibility of an error before you are even allowed to touch the successful case.

Post reply on HN