(no title)
jpalepu33 | 1 month ago
Having worked extensively with Node.js (callback hell, then Promises), I appreciate how error-as-value patterns force you to think about failure cases at every step. But the reality is most developers don't - they either:
1. Ignore the error case entirely (leading to silent failures) 2. Bubble everything up with generic error handling 3. Write defensive code that becomes unreadable
Rust's Result<T, E> with the ? operator found a sweet spot - you have to acknowledge errors exist, but the syntax doesn't make it painful. The key innovation is making the happy path concise while forcing acknowledgment of errors.
For Kotlin specifically, I'm curious how this interops with existing Java libraries that throw exceptions. That's always the challenge with these proposals - they work great in greenfield code but break down at library boundaries.
The real question: does this make developers write better error handling code, or just more verbose code? I'm cautiously optimistic.
HendrikHensen|1 month ago
There would be real value in a language which would have both.
Error values are perfect for un-exceptional errors, e.g. some states of a business logic. The name that the user entered is invalid, some record is missing from the database, the user's country is not supported. Cases that are part of the business domain and that _must_ be handled, and therefore explicitly modeled.
Then there is the grey area of errors that one might expect (so not truly exceptional) but are not related to the business logic. These could be for example network timeouts, unexpected HTTP errors (like 503), etc. For those, there is often no explicit handling in the domain that makes sense. So it's convenient to just throw an exception, let it automatically "bubble" to the highest level (e.g. the HTTP controller) and just return some generic error (such as HTTP 500).
There are also truly exceptional cases, that you really shouldn't encounter in your program, such as null-dereferences, invalid array index access, division by zero, etc. These indicate a bug in the code (and might be introduced explicitly with assert-style checks). The program is in an unknown, compromised state, so there's really nothing left to do than throw an exception or panic. An error value makes very little sense in this case.
I often have the discussion with friends, why a division operator, or an array access, doesn't return a `Result` type in nice languages such as Rust? Surely, if they care about error values, then each operation that can fail, must return a `Result` rather than panic (throw an exception). It is an interesting through experiment at least.
josephg|1 month ago
Rust has standard library functions to do this, if you want. arr.get(index) returns an Option. Integer types have .checked_div for panic-free divide. Float already doesn’t panic on an invalid division - it just returns NaN or Infinity.
frumplestlatz|1 month ago
Of course it's convenient to be able to ignore error paths when you're writing code. It's also a lot less convenient when those error paths cause unexpected runtime failures and data corruption in production.
A preference for unchecked exceptions is one of my most basic litmus tests for whether a developer prioritizes thinking deeply about invariants and fully modeling system behavior. Those that don't, write buggy code.
Tyr42|1 month ago
I mean, this could be a syntax wrapper for java checked exceptions right?
Those are isomorphic to Result<_, Err> in that you must handle or propagate the error. The syntax is different, sure.
hackthemack|1 month ago
One thing I notice in enterprise java software that I have to reed through and update, is that too many times, every developer just wraps everything in an exception. I do not have vast insight into all java code, everywhere, but in my little corner of the world, it sure looks like laziness when I have to dig through some ancient java code base.