6 ms·
> Exceptions do this automatically for you by default (you need to explicitly override it with a try/catch block) but alternative approaches, such as railway or
by piaste 3y ago
> Exceptions do this automatically for you by default (you need to explicitly override it with a try/catch block) but alternative approaches, such as railway oriented programming, require you to add in a whole lot of extra boilerplate code that is easy to forget and easy to get wrong.
The unfortunately missing part of exceptions (in mainstream languages) is that they handle this invisibly. Figuring out, at compile time, what sort of exceptions can appear inside a given function is not obvious.
That's the big payoff of ROP: you can look at any function signature and immediately know what sort of errors can come out of it.
Mitigating the downside of ROP (boilerplate) can be done to various extents, depending on the language. Haskell has do-notation. In F#, using the result computation expression [0] can make your code extremely clean:
type LoginError = InvalidUser | InvalidPwd | Unauthorized of AuthError
let login (username : string) (password : string) : Result<AuthToken, LoginError> =
result {
// requireSome unwraps a Some value or gives the specified error if None
let! user = username |> tryGetUser |> Result.requireSome InvalidUser
// requireTrue gives the specified error if false
do! user |> isPwdValid password |> Result.requireTrue InvalidPwd
// Error value is wrapped/transformed (Unauthorized has signature AuthError -> LoginError)
do! user |> authorize |> Result.mapError Unauthorized
return user |> createAuthToken
}
Could we do the reverse, i.e. mitigate the downside of exceptions? Is there a linter, code analyzer, or some other compile-time tool that can integrate with a Java IDE and automatically display the uncaught exceptions that might be thrown by a given line of code?
[0] https://demystifyfp.gitbook.io/fstoolkit-errorhandling/fstoolkit.errorhandling/result/ce https://demystifyfp.gitbook.io/fstoolkit-errorhandling/fstoo...
- bertylicious 3y agoJava has/had a compiler check that forced you to write catch blocks or `throws` annotations in/on functions that call other functions which might throw. The feature is called "checked exceptions" and I believe it has been discarded for its inconvenience by now. Sometimes it feels like developers are going in circles while trying to find the most optimal way to handle errors.
- brabel 3y agoPeople are now realizing that having the errors a function can cause right in the type system may actually have been a good idea, but when you point out that Result is not the only way and that Java checked Exceptions do the exact same thing (and so does the Zig error handling mechanism which is a third variant of the idea), they come up with all sorts of easily dismissable nonsense to explain why the two are very different.
- oblio 3y agoWhat would you reply to this comment: https://news.ycombinator.com/item?id=37174698 https://news.ycombinator.com/item?id=37174698
- layer8 3y agoI’m not the parent, but exception declarations are IMO necessary for a stable API contract. It’s exactly the same reason why return types are explicit. The actual issue in Java is that you can’t abstract over an arbitrary-length list (sum) of checked-exception types (variadic type parameters) (with the exception of rethrowing from multi-catch clauses).
- brabel 3y agoWell, that's kind of true! The fact checked Exceptions are inconvenient doesn't change the fact they are equivalent to returning a Result type (the implementation is obviously different but I think we don't need to mention that). A future version of Java could totally make it more convenient, and perhaps even make the implementation cheaper such that it would not just nearly the same , but literally the same as in Rust or other similar languages.
- piaste 3y agoDoes it even need a new language version? If the compiler already spits out the error "hey, your Fart() function should be annotated with 'throws ButtsException'", couldn't an IDE relatively easily be configured to automatically add the " throws " annotations?
- jammycakes 3y ago> The unfortunately missing part of exceptions (in mainstream languages) is that they handle this invisibly. Figuring out, at compile time, what sort of exceptions can appear inside a given function is not obvious. Figuring out, at compile time, what sort of exceptions appear inside a given function is a futile exercise in many contexts, and railway oriented programming does not fix it. Java tried this with checked exceptions and it fell out of favour because it became too unwieldy to manage properly. In any significantly complex codebase, the number of possible failure modes can be significant, many of them are ones that you do not anticipate, and of those that you can anticipate, many of them are ones that you cannot meaningfully handle there and then on the spot. In these cases, the only thing that you can reasonably do is propagate the error condition up the call stack, performing any cleanup necessary on the way out. "Handling this invisibly" is also known as "convention over configuration." In languages that use exceptions, everyone understands that this is what is going on and adjusts their assumptions accordingly.
- naasking 3y ago> Java tried this with checked exceptions and it fell out of favour because it became too unwieldy to manage properly. Because they did a half-assed job of it, and required the user to explicitly propagate error signatures. Inference and exception polymorphism are essential.
- Karunamon 3y agoChecked exceptions always seemed to me to be an exercise of self-flagellation and enumerating badness; when most of the time there are a handful of specific errors that require special handling, with everything else logged/return error/possibly crash.
- layer8 3y agoThe problem is that the callee can’t decide for the caller which exceptions will require special handling. And for the caller to be able to make an informed decision about that, the possible exceptions need to be documented. Since this includes exceptions thrown from further down the call stack, checked exceptions are about the only practical way to ensure that all possible failure modes get documented, so that callers are able to properly take them into account in their program logic.