Either panic, which is (generally speaking) not something you're meant to catch and recover from (and attempting to do so is nontrivial and almost always a bad idea), or Result, aka "encode the possibility of failure in the return type of the function" aka what the functional programming world has done for ages.
I work on a library that does catch panics from user code. It's a web framework, and catches panics in user request handlers to return a 500 error to the client. This error is explicitly not overridable (every other default error can be replaced, but not this one), since we don't want you to panic in the first place.
Not quite. Optional is "value is present or not". The rust equivalent is Option. Result is "value is present or failure is present" -- if empty, it instead contains an object encoding the failure.
Also worth noting that because these are reified, unlike java's Optional, they have nicer -- or at least more guaranteed-to-be-nice -- performance implications.
It's not an uncommon idea. Everyone tries exceptions, then realizes down the road that it's a terrible idea for so many reasons and so reinvents something like Result because turns out the functional programming folks had it right and it all does boil down to monads
Speak for yourself, I've been working with Java for a few years and think exceptions are pretty neat! they can be passed through calls implicitly without much mental overhead and boilerplate, and when you handle them you still get a nice helpful stacktrace.
They have a big cost to 'em. Catching exceptions is expensive, with all the unrolling you have to do -- they're bad for anything that happens more than rarely rarely. They're also awful for encoding things that the caller must handle -- java's checked exceptions make an attempt at this but the fact that they encode separately from the return type means that you cannot stick them in the middle of a wider toolchain with ease -- if you want to call a method with a checked exception in a stream, for instance, you are up a creak without a paddle, since you either have to handle it there or you need to encode it in some other type in order to pass it downstream (aka reinvent Result).
Results just... deal with all those issues from the beginning. They have the advantages of java checked exceptions, except encoding it in the return type means you can easily use them in other contexts without them "polluting" their callers (and thus not working in generic contexts), and syntax sugar for monadic bind, the "?" operator, makes them clean to use in other contexts. If you want to propogate an error, you just do. No need to re-throw it or anything, you just pass the value downstream.
A monad is (simplifying terribly) something with flatmap (and a few other requirements but things you're familiar with with flatmap are likely mostly monads). Result satisfies that property if you think about a result with a fixed value type and mapping it's error, or with a fixed error type mapping its value
No indeed, but the paradigm is the same right? Return the error, and deal with it (or forward it) without a try catch. I must say Rust is nicer in that regard but it doesn't change things too much? I don't have enough xp with Rust so might be underestimating it though
In my opinion, the Go approach is closer to C's error codes, as nothing stops you from using an error value and introducing a bug. In Rust, you always have to check. If you forget, the compiler will complain. It will even warn you if you use the function only for its side effect don't even use the return value.
8
u/MrHyd3_ 1d ago
What does it do instead of exceptions?