I think it's fair to say that having some sort of syntactically lightweight sum or union type facility makes this way nicer than anything Java ever had -- subclassing isn't really a solution, because you often want something like:
type FooError = YoureHoldingItWrong | FileError
type BarError = YoureHoldingItWrong | NetworkError
fn foo() -> Result<int, FooError> { ... }
fn bar() -> Result<int, BarError> { ... }
fn baz() -> Result<String, BarError> { ... }
TypeScript's type system would hypothetically make this pretty nice if there were a common Result type with compiler support.Rust needs a bit more boilerplate to declare FooError, but the ? syntax automatically calling into(), and into() being free to rearrange errors it bubbles up really help a lot too.
The big problem with Java's checked exceptions was that you need to list all the exceptions on every function, every time.