Live data from Hacker News

Kotlin's rich errors: Native, typed errors without exceptions

cekrem.github.io

21–30 of 84 posts

Re: Kotlin's rich errors: Native, typed errors without exceptions

#21

The discussion around checked vs unchecked exceptions always comes down to ergonomics vs safety. 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 e…

Similar thoughts.

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.

Re: Kotlin's rich errors: Native, typed errors without exceptions

#22
Does anyone know of a great write up on exceptions vs union or either typed returns?

I'm building a new language, somewhat similar to TypeScript in some ways, and so far I have exceptions and try/catch expressions, but also Optional and Result types.

I'm familiar and used to exceptions, so I included them so at least near-fatal errors (ie, actually exceptional) could be caught at high levels in the stack. But I'm unsure if there's a strong argument that resonates with me yet that the language shouldn't have exceptions at all. Arguments that exceptions are untyped can be solved with things like checked exceptions, and I do find Go-style code to be quite verbose.

What's the best current reading on this?

Re: Kotlin's rich errors: Native, typed errors without exceptions

#23
post #8

Rich Errors look promising to me, but what about interop with Java? What will the return-type of a function be on the Java side be, if the return type on Kotlin side is: Int | ParseError | SomeOtherError? Background: unions aren't restricted to one normal type and one error type, but to one normal type and any number of error types, so this can't be modelled as syntactic sugar on top of an implicit Either/Result type…

Kotlin folks seem to mostly care about Java as bootstrap to their own ecosystem. The anti-Java bias, against the platform that made it possible in first place and got JetBrains a business, is quite strong on Android, fostered by the team own attitude usually using legacy Java samples vs Kotlin.

Android folks have good reason to have anti-Java bias. Their bias, as it happens, is against old Java, which they are constrained to use as fallout from the Oracle lawsuits of yore. Kotlin breathed new life into Android in a meaningful way.

On backend teams, I've not personally encountered much anti-JVM bias - people seem to love the platform, but not necessarily the language.

(yes I know there's desugaring that brings a little bit of contemporary Java to Android by compiling new constructs into older bytecode, but it's piecemeal and not a general solution)

Re: Kotlin's rich errors: Native, typed errors without exceptions

#24

The discussion around checked vs unchecked exceptions always comes down to ergonomics vs safety. 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 e…

The biggest problem is that people treat it as a dichotomy: either exceptions or error values. But that's a false dichotomy. 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…

> why a division operator, or an array access, doesn't return a `Result` type in nice languages such as Rust?

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.

Re: Kotlin's rich errors: Native, typed errors without exceptions

#25
post #17

Earlier quoted context omitted.

The biggest problem is that people treat it as a dichotomy: either exceptions or error values. But that's a false dichotomy. 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…

Sounds like checked and unchecked exceptions. I mean, this could be a syntax wrapper for java checked exceptions right? Those are isomorphic to Result in that you must handle or propagate the error. The syntax is different, sure.

Correct. Although the performance characteristics are different. An exception in Java generates a stack trace, which is relatively expensive. So not a great idea in un-exceptional code paths that need to perform well.

Re: Kotlin's rich errors: Native, typed errors without exceptions

#26
post #24

Earlier quoted context omitted.

The biggest problem is that people treat it as a dichotomy: either exceptions or error values. But that's a false dichotomy. 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…

> why a division operator, or an array access, doesn't return a `Result` type in nice languages such as Rust? 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.

That's great! Though, by making it not forced and giving users a choice, you never know which library code you call might not use those features and still panic when you use it.

(Just to be clear, I don't really propose that a language should offer only panic-free operations; I just think it's a nice thought experiment and discussion to have).

Re: Kotlin's rich errors: Native, typed errors without exceptions

#27
post #7
post #3

The Java interop compromise is probably the biggest weakness of the proposal - it works beautifully within Kotlin but degrades at boundaries. This is similar to how Kotlin's nullable types (String?) become platform types in Java. I think it's good nonetheless to add stuff to Kotlin that won't translate 1:1 to Java, both because Java is evolving but also because Kotlin is used in "Native" (non-JVM) contexts as well (n…

That is always the gotcha with guest languages. C++ cannot get away from C, Typescript cannot get away from JavaScript, and so forth.

That is more interoperability than guest language situation. I don’t think c++ is a c guest. Ts has a different approach to the js self.

Re: Kotlin's rich errors: Native, typed errors without exceptions

#28
post #8

Earlier quoted context omitted.

Kotlin folks seem to mostly care about Java as bootstrap to their own ecosystem. The anti-Java bias, against the platform that made it possible in first place and got JetBrains a business, is quite strong on Android, fostered by the team own attitude usually using legacy Java samples vs Kotlin.

Android folks have good reason to have anti-Java bias. Their bias, as it happens, is against old Java, which they are constrained to use as fallout from the Oracle lawsuits of yore. Kotlin breathed new life into Android in a meaningful way. On backend teams, I've not personally encountered much anti-JVM bias - people seem to love the platform, but not necessarily the language. (yes I know there's desugaring that brin…

Lies, damm lies.

They cherry pick whatever they feel like from OpenJDK.

And even though Oracle was right, given that Android is Google's J++, in this case they had better luck than Microsoft.

They don't take more from OpenJDK because then their anti-Java narrative doesn't work out.

But there is some schadenfreund, to keep Kotlin compatibility story relevant they are nonetheless obligated to keep up with is mostly used on Maven Central, thus the updates up to Java 17 subset.

Re: Kotlin's rich errors: Native, typed errors without exceptions

#29

Rich Errors look promising to me, but what about interop with Java? What will the return-type of a function be on the Java side be, if the return type on Kotlin side is: Int | ParseError | SomeOtherError? Background: unions aren't restricted to one normal type and one error type, but to one normal type and any number of error types, so this can't be modelled as syntactic sugar on top of an implicit Either/Result type…

by default it'll be exposed as a `java.lang.Object` and they've thought about using compiler plugins to generate methods returning `Optional` or `Result` instead

https://www.youtube.com/watch?v=IUrA3mDSWZQ&t=2626s

Re: Kotlin's rich errors: Native, typed errors without exceptions

#30

Does anyone know of a great write up on exceptions vs union or either typed returns? I'm building a new language, somewhat similar to TypeScript in some ways, and so far I have exceptions and try/catch expressions, but also Optional and Result types. I'm familiar and used to exceptions, so I included them so at least near-fatal errors (ie, actually exceptional) could be caught at high levels in the stack. But I'm uns…

One of the most thorough articles on error handling in programming language design that I've read is this one: https://joeduffyblog.com/2016/02/07/the-error-model/. It was written by Joe Duffy, who worked on Microsoft's experimental Midori language.

Another relevant article is Robert Nystrom's "What Color is Your Function?": https://journal.stuffwithstuff.com/2015/02/01/what-color-is-... This article is about async/await, but the same principles apply to error handling. This article uses colors as an analogy, but is really about monads.

Both IO and exceptions can be denoted as a monad. What this means is that a function inside the programming language, A -> B, can actually be denoted by a mathematical function of the signature [[A]] -> M [[B]], for some monad M. For example, if we are dealing with the exception monad, M would be _ + Exception.

A language such as Java implicitly executes in the IO + exception monad. However, the monad can also be exposed to the programmer as an ordinary data type, which is what Haskell does. When people talk about the tradeoff of exceptions versus Result, or the tradeoff between preemptive concurrency and async/await, they are really talking about the tradeoff between making the monad implicit or explicit. (A language where all functions may throw is like one where all functions implicitly return Result. A language where all functions may be preempted is like one where all functions are implicitly async, and all function calls are implicitly await points.)

The theoretical technique of using monads to model the implicit effects of a programming language was pioneered by Eugenio Moggi, and the idea of making them explicit to the programmer was pioneered by Philip Wadler.

Something else to think about is how monads stack. For example, how would you handle functions that are both async/await and throw exceptions? Does the answer change when the monad is implicit (e.g. throwing exceptions) or explicit (e.g. returning a result)?

Post reply on HN