Hacker News new | past | comments | ask | show | jobs | submit login

> The litmus test for panic! vs. Result<T,E> is not rarity of occurrence, it's whether the condition represents a programming bug or a recoverable error.

Because that exact same conceptual separation worked so well for Java with checked vs unchecked exceptions...

Everyone just started using unchecked exceptions because they provide an easier coding experience.

Also, there's legitimate situations where the library cannot make that decision, but rather the user. As someone else says in another example, who are you to say that my request to allocate too much memory is a panicable offense? What if my program can, in fact, recover from that situation?

At least in Java, catching checked vs unchecked exceptions is the same if you do choose to handle them.




> > The litmus test for panic! vs. Result<T,E> is not rarity of occurrence, it's whether the condition represents a programming bug or a recoverable error. > Because that exact same conceptual separation worked so well for Java with checked vs unchecked exceptions... > Everyone just started using unchecked exceptions because they provide an easier coding experience.

Indeed. That's a problem with exceptions and checked exceptions and the choices in Java around that, not the idea that operational and programming errors might be handled differently.

> Also, there's legitimate situations where the library cannot make that decision, but rather the user.

What you're describing is that different components may choose to treat these separately. That's fine -- there doesn't need to be an objective answer. You can have one library say "allocating too much memory is not an error we care to deal with and we treat that as a programmer error". And people using that can be told that's a limitation. That's fine. All components have limitations. Another library that implements the same thing can say "we treat allocating too much memory as a recoverable operational error and express it in this way". It's all tradeoffs.

That also doesn't mean _all_ such cases are subjective. Another comment mentioned an index out of bounds in quicksort. That's completely within the control of the implementation and in most contexts there's no reason that should ever be a recoverable error.


> Everyone just started using unchecked exceptions because they provide an easier coding experience.

I think that's true, but I think there's some ambiguity about what sort of "easier coding experience" mattered. I feel like it's often portrayed as "too lazy to write the annotations", but in practice the language to describe exceptions is often too limited to express what we'd want. As a trivial example, we'd like to be able to say "map() can throw anything its argument can throw". That we can't say that means a programmer working with checked exceptions needs to either catch and suppress things they shouldn't be suppressing in that function passed to map(), or build clever (and possibly inefficient) workarounds to extract the exception(s?!?) anyway. All of that has drawbacks enough that the downsides of unchecked exceptions may be the correct choice, not merely the lazy choice.


> Everyone just started using unchecked exceptions because they provide an easier coding experience.

This is because checked exceptions, contrary to Result, are much more limited/annoying e.g. they don't compose well with lambdas, can't be generic, and don't offer those nice functional combinators.


> Java with checked vs unchecked exceptions

Java doesn't make it nice to deal with exceptions though. Converting a checked exception into an unchecked exception is incredibly wordy:

    int output;
    try {
        output = doSomething();
    } catch (IOException io) {
        throw new RuntimeException(io);
    }
vs Rust's method of defaulting an error result to a panic:

    let output = doSomething().unwrap()
https://doc.rust-lang.org/std/result/


Its very different from Java.

In Java and many other languages, the expectations are declared at the callee site, which is a completely wrong place to do it. Only the caller knows whether the situation is expected or not.

Lets say I'm trying to get the element at index 20 of some array-like datastructure.

Lets say that returns a `Result<T, E>`.

Lets add another twist: I've already checked whether the length is > 30 for other resons in that same block. Therefore, I know (if borrowing mechanisms ensure the absence of concurrency issues) that getting the 20th element will not cause an error. In this case I can use

  my_obj
    .element_at(20)
    .expect("Unexpected missing element at index 20 even though number of elements is > 30")
As a caller, something is very wrong in this situation. If so, I can make the choice (doesn't work for all types of programs) to abort immediately.

edit: see other comments in the thread for a more believable quicksort example, where you are getting the element at `len/2` as pivot.

This is a somewhat certain situation. You can also use this in softer situations, like e.g. a program that just can't run if its data file (large language model files, for example) cannot be found in `$PWD` because say, the docker image is always built in a way that includes it and you wrote it to only run within that image. As a caller, its up to you to decide whether this situation is expected / recoverable or not. (Yes you might criticize that rigid choice, but if the choice is correct, so is the behavior to abort if the condition is not satisfied)

You can also decide that the callee doesn't know whether the error is expected and "propagate" the error further by ensuring the function returns a Result<T, E> using the `?` operator.

Rust is one of the rare languages that gets this right. (Swift does too [1] - i am not quite aware of others)

[1]: https://docs.swift.org/swift-book/documentation/the-swift-pr...


Checked exceptions aren’t really compatible with generics. You can’t pass a lambda and have the compiler infer its exception list now applies to the caller.


aye - in Java, this inevitably leads to strange catch Exception/RuntimeException statements all over the code. In practice, there are very few/no reasons to order a program crash. Programming errors are inevitable on a large code base, we learned the hardway in kernel development that Blue Screen Of Death is not the correct outcome for an error.


> Everyone just started using unchecked exceptions because they provide an easier coding experience.

Yes, in much the same way that no longer checking for error codes provides an easier coding experience.

But it makes your code more crashy.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: