Thursday, 25 September 2025

Kotlin Unit

When I wrote this post and mentioned the Kotlin use function for Automatic Resource Management I had some doubts about the signature. It's a generic function that returns R:


inline fun  T.use(block: (T) -> R): R

which fits so nice in the more functional style code I was discussing in that post, but what if we want to do something on that closable resource without returning any value? Well, the thing is that the function signature is also valid for that case, as in Kotlin what I mean by "not returning anything" (I'll be careful not to say "returning nothing" as in Kotlin Nothing has a particular meaning) means indeed returning Unit, a singleton object/class descending from Any, so that perfectly fits with the T generic type.

Having said this, it feels interesting to me to review how this "not retuning anything" works in different languages and compare it to the Kotlin approach and its advanced type system.

In Java and C# functions that do not return anything are marked as returning void. void is indeed a keyword representing "no return value" - it's not part of the normal type hierarchy.

In Python a function that does not have an explicit return statement or just does "return" without providing a value is indeed returning None (that is the single instance of the NoneType singleton class). If using type hints, mypy will consider correct that a function defined as returning Any returns None (as None is just a normal objec). In JavaScript the lack of an explicit return statement (or a simple "return;") will return the undefined value (JavaScript has this messy distinction between undefined and null that feels more accidental than intentional). For dynamic languages where type checking has come as an after thought (either directly in Python via typing or indirectly in JavaScript via its TypeScript "friend") this seems OK, but static languages things have to be more strict.

Kotlin elegantly establishes a subtle difference between functions that can return a value or the absence of that value, and functions that never return anything useful. For the former we use as return a nullable type. A getUser(id) function returns User? cause it returns a User if the id exists or null if that's not the case. On the other hand a writeLog() function returns Unit because it never returns anything useful. In Python we don't have that subtle difference, both write_log and get_user for missing id return None. With this, we can say that:

  • Kotlin uses Unit for "no meaningful value" and null for "the absence of an expected value"
  • Python lacks the semantic distinction between "no meaningful value" vs "absent value"

As I said at the start of this post I've been saying "does not return anything" (I should better say "does not return anything useful") rather than "returns nothing" because as I mention in this post Nothing has a special meaning in Kotlin. It's a bottom type, used for expressing that a function does not return (throws an exception, it's an infinite loop...). There's a good discussion here. I think Nothing is a confusing name, I prefer the naming used in Python typing for the same concept Never and NoReturn (both types are equivalent).

I was wondering, what if we want to declare a Kotlin function that always returns null? Well, probably that does not make much sense and we should just declare it as returning Unit. Googling around I've found this discussion where they propose returning Nothing?. They support the idea by copy-pasting a fragment of the documentation that does no longer seem to exist in the current documentation, so maybe the Kotlin designers just discarded that notion.

As a conclusion, in languages like Kotlin, Python or JavaScript we should not think about functions that do not return anything (save for functions that crash). All functions that finish naturally return something, but that something can be a not usable value (Unit) or an absent value(null, None, undefined).

No comments:

Post a Comment