Remix.run Logo
pema99 a day ago

Not really. Exceptions usually imply unwinding the stack, and the ability to catch at any point throughout the callstack. Result types are just 'dead' data.

zozbot234 a day ago | parent [-]

These are fully equivalent in outcome, though often not low-level implementation. You can use try...catch (called panic...recover in Go) to pack a normal and abnormal return case into the equivalent of a Result<> type. Or just pass an abnormal Result<> back to the caller to manually unwind a single "layer" of the call stack.

biorach a day ago | parent [-]

> These are fully equivalent in outcome

They are so different in DX, ergonomics, implementation and traceability that I'm not sure this is true other than in the most abstract sense

sshine a day ago | parent [-]

There is some DX similarity between checked exceptions and Result types.

Because the compiler will fail if you don't explicitly mention each possible exception.

But checked exceptions are coming out of style: They're unchecked in C#, and frameworks like Spring Boot in Java catch all checked exceptions and rethrow them as Spring Boot flavored unchecked ones.

For unchecked exceptions and Result types:

The DX is very different in one critical way:

With Results you constantly have to differentiate between error and ok states, before you proceed. With unchecked exceptions you generally assume you're always in an ok state. It's equivalent to wrapping your whole function body in 'try { ... } catch (Exception e)'. And you can get that with Result types in Rust by using '?' and not worry about doing something half-way.

Ultimately: Are you a happy-path programmer?

Arnavion a day ago | parent [-]

>Because the compiler will fail if you don't explicitly mention each possible exception.

But only the first time. Once you add `throws FooException` to the caller signature, the compiler won't complain about any future callees that also happen to throw FooException, even if you did care about handling their exceptions yourself. With callees that return Result you do get to make that decision for every callee.

sshine an hour ago | parent [-]

That's a fair distinction.

I would say "adding Result to the caller signature" provides a similar cascade, but it's not entirely true: Every call must separately be unwrapped. So consistently wrapping your Result calls with the '?' operator is similar to a gigantic try-catch block or adding 'throws CheckedException' everywhere.

So both the '?' operator and adding 'throws CheckedException' everywhere let you accidentally neglect proper error handling: You have a default that is syntactically almost invisible and frees you from thinking. The checked exceptions give you a little more freedom from thinking than the '?' operator.