Live data from Hacker News

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

msirringhaus.github.io

171–180 of 204 posts

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

#171
post #169

Earlier quoted context omitted.

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…

I don't agree with your first or third paragraphs but I do kind of agree with the second, yet I think the solution to that is to provide return-value-based solutions where it makes sense, not to avoid exceptions in general.

Also, things like "user canceled this operation" are great for exceptions IMO... exactly how would you stop (say) a sort() function otherwise? You'd need to write a custom cancelable sort, which isn't a great idea? You can't reinvent the wheel for everything.

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

#172
post #68

Earlier quoted context omitted.

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

But design and coding are different steps, best kept separate. When you are designing, I agree with you, the expected usage is very important. But in the design step the particular language mechanism for dealing with conditions does not matter. Once you get a specification to program to, all input conditions can be treated as equal. That is, unless you need to optimize heavily by biasing your execution path for a cer…

Ideally yes, but most of the time I find I have no idea about what I want to do. Idea leads to code, code reveals constraints, those lead to other ideas. If we could specify things, code writing AI would be easy. But most of the time, we just have no idea.

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

#173

Earlier quoted context omitted.

I totally agree. I love Swift's guard let. It makes early returning [1] easy: guard let value = optvalue else { return // optvalue is none } There has been several proposals [2][3] to fix it in Rust but they don't seem to go anywhere. I'm using this in my own code now to unwrap or return (it looks stupid): let value = if let Some(value) = optvalue { value } else { // optvalue is none return; }; [1] https://szymonkraj…

I missed `guard let` for a while too, but eventually stumbled upon this pattern which is almost as good: let value = match value { None => return, Some(value) => value };

I use match as an inside out 'if let' but in this particular case I prefer to:

  let value = value.ok_or(MyError)?;

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

#174

Earlier quoted context omitted.

I mean, Go's error handling is one of the worst implementations of the "error code" idea, so it is a bit unfair to disregard the idea just because one particular implementation is bad. You should try Rust or Swift, at least the error handling part, to fully appreciate what a good error code implementation could be.

I'd love to when I get a chance. I did see that Rust seems to favor a ? macro that seems to make error codes behave essentially like exceptions, so I am curious to try it out at some point and see if that ends up being any different from exceptions in practice.

The "?" operator doesn't turn them into exceptions, it's just a "return-early-if-error" shortcut. The main difference being that the caller still has to handle the error of a function using "?". (even if it's by punting further up the call stack with more "?", which you could argue is exactly how exceptions work, but it is at least explicit in what functions can fail and which don't)

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

#175
post #99

Earlier quoted context omitted.

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

I don't really understand this criticism, because there's no good alternative. Every language is capable of producing invalid states that the programmer did not intend; consider `x / user_input()`. (Unless literally every possible invariant of the program is expressed in the type system, which is not something that we have figured out how to do at scale and not something that even the most type-heavy of the popular l…

So you want your kernel to panic whenever it runs out of memory?

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

#176
post #99

Earlier quoted context omitted.

I don't really understand this criticism, because there's no good alternative. Every language is capable of producing invalid states that the programmer did not intend; consider `x / user_input()`. (Unless literally every possible invariant of the program is expressed in the type system, which is not something that we have figured out how to do at scale and not something that even the most type-heavy of the popular l…

> I don't really understand this criticism, because there's no good alternative. There's the option of surfacing the panic-ability of a function in the same way the constness is surfaced, which would allow some subsets of the code to ensure they won't call a possibly-panicing thing, even at the cost of convenience.

In the cases where the problem is actually panicing (ie, a non-total function) rather than your choice of core-dumping code, lack of panic-ability is strictly insufficient - `while(1){/*busy-loop*/}` is exactly as bad as `panic();`, and what you actually need is not "must never panic", it's "must make forward progress within some (not necessarily rigorously defined but) small amount of time". That doesn't have anything to do with panic besides that `panic` would be declared as `fn(string)->noreturn[takes_upto: (infinity * seconds)];`, rather than just `fn(string)->noreturn`. (And really, noreturn ought to be enough to infer that on its own.)

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

#177

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

> To fix that, you need to start supporting error polymorphism.

  > map :: List a -> (a -> b -[err]) -> List b -[err]
FWIW, Haskell has this already; it's called[0] Traversable:

  ghci> :t mapA
  mapA :: (Traversable t,Applicative f) => (a -> f b) -> t a -> f (t b)
  ghci> :t mapA @(Error ||) @[]
  mapA :: (a -> Error || b) -> [a] -> Error || [b]
0: The default prelude calls it `traverse` instead of `mapA` (which is terrible for reasons that should be obvious[1]) and `Either Error a` instead of `Error || a` (which is a matter of taste).

1: Especially if you rename the method of Functor from `fmap` to:

  map :: Functor t => (a ->   b) -> t a ->    t b
  -- for comparison:
  mapA :: ...      => (a -> f b) -> t a -> f (t b)

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

#178
post #99

Earlier quoted context omitted.

I don't really understand this criticism, because there's no good alternative. Every language is capable of producing invalid states that the programmer did not intend; consider `x / user_input()`. (Unless literally every possible invariant of the program is expressed in the type system, which is not something that we have figured out how to do at scale and not something that even the most type-heavy of the popular l…

So you want your kernel to panic whenever it runs out of memory?

Yes, for servers! Hard failures are much easier to deal with than soft-not-dead-but-still-useless states.

echo 1 > proc/sys/vm/panic_on_oom

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

#179

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…

I'm confused. Isn't that just C? There's no errors in C, or exceptions. The only exceptions are interrupts/signals, but those aren't part of the language, but the machine or OS.

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

#180
post #14

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…

I've found the rust debugging experience to be very primative. When you say modern tools, are you describing rr? As far as I know that doesn't reliably integrate with rust?

I've used gdb just fine on Rust code. Pretty printing isn't always as good, but if Rust is crashing, I'm probably down towards the syscall level anyways (or blowing the stack size as my last observed crashes were triggering).
Post reply on HN