| ▲ | armchairhacker 2 hours ago | |||||||
These remind me of checked exceptions in Java. Ironically, Kotlin removed checked exceptions because they tend to be annoying more than useful: there's no clear guideline to whether an exception is checked or unchecked, some functions like IO and reflection have them while others don't, they're verbose especially when closures are involved, and lots of functions simply catch and rethrow checked exceptions in unchecked exceptions. Which leads me to: why is Kotlin implementing this in a non-JVM compatible way, instead of introducing checked exceptions with better language support? All the problems stated above can be avoided while keeping the core idea of checked exceptions, which seems to be the same as this proposal. From the GitHub discussion, I see this comment (https://github.com/Kotlin/KEEP/discussions/447#discussioncom...): > The difference between checked exceptions from java and error unions in this proposal is how they are treated. Checked exceptions are exceptions and always interrupt the flow of execution. On the other hand, errors in this proposal are values and can be passed around as values or intentionally ignored or even aggregated enabling the ability to use them in async and awaitAll etc. But is this a real difference or something that can be emulated mostly syntactically and no deeper than Kotlin's other features (e.g. nullables, getters and setters)? Checked exceptions are also values, and errors can be caught (then ignored or aggregated) but usually interrupt the flow of execution and get propagated like exceptions. | ||||||||
| ▲ | Tyr42 a minute ago | parent | next [-] | |||||||
[delayed] | ||||||||
| ▲ | loglog an hour ago | parent | prev | next [-] | |||||||
The plain Java equivalent of the proposed semantics would be a type system extension similar to JSpecify: @Result(ok=Ok.class, error={Checked1.class, Error2.class}) Object function() combined with enough restrictions on the usages of results of such methods (e.g., only allow consuming the results in an instanceof pattern matcher; not even switch would work due to impossibility of exhaustiveness checking). The one feature that the proposed Kotlin error types share with Java checked exceptions is that they can be collected in unions. However, the union feature for checked exceptions is pretty much useless without the ability to define higher order functions that are generic over such unions, which is why checked exceptions fell out of favor with the spread of functional APIs in Java 8. | ||||||||
| ▲ | sirwhinesalot 2 hours ago | parent | prev [-] | |||||||
Exceptions are cheap on the happy path and super expensive on the error path. Checked exceptions only make sense for errors that are relatively common (i.e., they aren't really exceptional), which calls for a different implementation entirely where both the happy path and the error path have around the same cost. This is what modern languages like Rust and Go do as well (and I think Swift as well though don't quote me on that) where only actually exceptional situations (like accessing an array out of bounds) trigger stack unwinding. Rust and Go call these panics but they are implemented like exceptions. Other errors are just values. They have no special treatment besides syntax sugar. They are a return value like any other and have the same cost. As they aren't exceptional (you need to check them for a reason), it makes no sense to use the exception handling mechanism for them which has massively skewed costs. | ||||||||
| ||||||||