TL;DR: I'd definitely recommend using RxJava & RxKotlin.
To me, the two main problems of the “callback hell” in NodeJS is the verbosity of the function syntax and the abscence of proper error handling.
ES6 will correct both problems with the lambda syntax and the standardized Promise library.
As fo Kotlin, the first problem is corrected by the language itself.
// Kotlin
downloadFile(url) { it.length }
// JS (ES 5)
downloadFile(url, function(file) { return file.length; });
<Digression>
Of course, the integration of a feature like async / yield would be tremendous but it needs a lot of work before it can be done. Having a look at how Dart integrated these in its latest version is very instructive. For Kotlin to have such a feature, it would need to:
- Support for async functions.
- Rely on a Future like object for such functions.
- Integrate nicely with Java, as it is one of Kotlin’s primary goal.
- Integrate nicely with usual thread based asynchronicity, we’re not going to rewrite all I/O libraries.
- implement a “coroutine” runtime inside the JVM. Easier said than done since the JVM is not asynchronous like NodeJS or Dart. That’s the hardest part, the JVM is just not thought for that.
I would be immensly greatful to the Kotlin team should they do it, but I don’t think it will be done tomorow.
For starter, if we could have a C# like yield (wich is an “intermediate return”, nothing to do with async), that would be great (and not that complicated, I think).
</Digression>
For error handling, I recommend using RxJava & RxKotlin. The problem with NodeJS like callback is that you have to check for error handling in each callback. Using RxJava & RxKotlin allows you to subscribe / chain / combine Observables (Future / Promise like superset) and handle any error only once.
RxJava is a real pain to learn and properly understand, but once you’re past learning it, it is amazing how asynchronicity becomes easy. Especially in Kotlin.
Furthermore, the Observable API provides a feature that is comparable to yield:
val obs = observable<Int> {
for (i in 1…5)
it.onNext(i)
it.onCompleted()
}
This will create an observable that will return all integers from 1 to 5 before completing. The execution will not hang at each call to onNext and all results will be stored waiting to be consumed, so it’s not yield per se, but it’s the closest we have now.
Hope it helps