It was explained before – Kotlin uses Unit
so that functions are regular.
Lambdas that don’t return a value don’t need special handling versus lambdas that do. Since all functions return something (except the ones that don’t return at all i.e. Nothing
:-)). Therefore we don’t need workarounds like the Java Consumer
and the Java Function
. In Kotlin, functions are not either Consumer
s or Function
s – they are just Function
s.
I agree the naming is not necessarily obvious, but other languages that support functional programming operate the same way. For example, Scala uses Unit
as well.
As I was writing this, I thought – wait a second, it can’t be the case that Swift functions are not regular – and indeed, I was wrong earlier. Swift functions with no return value DO actually return something: the empty tuple ()
, which Swift simply aliases to Void
:
typealias Void = ()
func f1() {
print("f1")
}
// a compiler warning, not an error!
let f = f1()
// prints `()`
print(f)
So that Swift code prints ()
which is not so different than your example code which prints kotlin.Unit
.
So if you think the Swift behavior is ideal, now you know Swift operates almost exactly like Kotlin. All we would have left to haggle over is naming and compiler warning behavior. The Kotlin compiler could probably be modified to emit a warning in that situation just like Swift does. So this isn’t a fundamental language concern.
If you didn’t know this about Swift Void, then its a good example of why using a different name is a good idea – it forces you to learn and understand as opposed to proceeding unchecked with an incorrect assumption, as I believe we were both doing with Swift.
You said:
Blocking is not about heavy operations. It is a Thread
that can’t do anything else because it is waiting for something. For example, the JVM Thread.sleep
method blocks a Thread
. In fact, a Thread that is doing heavy operations is not actually blocked, it is in a Runnable state.
Blocking simply means the thread is blocked and cannot move forward. This is standard terminology for Java threads. runBlocking
is meant solely as a bridge from the world of threads to the world of coroutines. It is therefore doing exactly what it says – it is blocking the current thread while waiting for the coroutine to finish i.e. that thread is blocked and cannot do any other work.
Its natural to be a bit confused when encountering new language constructs, but once understood I don’t see how this isn’t reasonably developer-friendly?
Yep. I explained earlier why I think suspend
was a better choice than async
/await
so I won’t rehash that. Its a valid point there is nothing in the code to indicate a suspension point (though IDEA shows it very clearly in the gutter). I haven’t found this to be a problem in practice.
You come from a Swift background? I come from a Java/Kotlin background and this is exactly what I think every time I use something new in Swift. Then after a while I learn how it works and think “yeah, that’s not too bad”. So mostly this is about language familiarity. But, I maintain that Kotlin by and large makes dev-friendly choices more often than not.