marko devcic

  • github:
    deva666
  • email:
    madevcic {at} gmail.com

First look at Kotlin's Coroutines

Posted on 13 May 2017

Before I started working on Android I’ve been mostly a C# developer. Switching to Java from C# for me was like traveling to the past.
No lambdas (Android doesn’t have support for Java 8), no type inference, functions are not first class citizens, just to name a few features that make your life as developer easy.
Another thing that makes me hate Java is the async programming model. To abstract low-level threading from you, Java uses Futures and Executors. And on Android, you have the AsyncTask class (which nobody is using anymore, right?).
Using Futures for some simple task, like doing a web request on a background thread and posting the result on the main thread usually ends up in a callback hell.
There are libraries like RxJava that can help you write async code, but they are not language features and in the case of RxJava it is a library for reactive, not async programming.
Compare this to C#’s Tasks and Task Parallel Library, where doing a work off the main thread is as easy as calling Task.Run and supplying an Action. Also, you have full control on which context the continuation resumes, making it really easy to post the result to the main thread.
But, the best thing is the async/await feature that was released with C# 5.0. Just to show how it looks, let's compare executing some asynchronous HTTP request in C# and in Java.

C#
public async Task GetResponseAsync(string url)
{
  HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
  //await marks the suspension point in the method. When result is available, the method resumes executing on the next line
  WebResponse response = await request.GetResponseAsync(); 
  return ParseResponse(response);
}
Java
public void GetResponse(String url){
    ExecutorService executor = Executors.newSingleThreadedExecutor(); 
    //HttpRequest is a custom class that implements Callable interface, code omitted
    Future response = executor.submit(new HttpRequest(new URL(url), new Callback(){
        public void onSuccess(Response response) {
            parseRespone(response);
        }
        
        public void onError(Throwable fail) {
            //log it
        }
    }));
}

C# code is written like it is executing synchronously, but the method is asynchronous. So, it is much easier to read. Also, a huge difference is that if C# async method is called from UI context, everything after await keyword will be executed on the Main thread.
Java's onSuccess callback method will be executed on the Executor's background thread, which means, even more, code is needed to see the result on the Main thread.
So it's pretty obvious why I like C# async programming model.

This asynchronous programming has been gaining a lot of traction recently. More and more languages are adopting it and have some way of suspending methods half way through. Javascript has async/await, Python 3 has coroutines. And I'm thrilled to finally see something like this in the JVM world. With Kotlin v1.1 we now have Coroutines. They are suspendable functions and underneath they are similar to C# async/await.
I won’t go into a tutorial mode with Coroutines, the official documentation is really good.
Since they are still experimental, a lot of things can still change. So in this post, I’ll show some real world usage examples and in the end, go over some things that I think could be improved. The current Coroutines library version is 0.13.

So, first a simple example. Given this Retrofit interface

interface GitHubAPI {
	@GET("/users/{name}")
	fun getUser(@Path("name") name:String) : Call<User>
}

A standard way of calling it would be something like this:

gitHubApi.getUser("userName").enqueue(object : Callback<User> {
			override fun onFailure(call: Call<User>, t: Throwable?) {
				//display the error
			}

			override fun onResponse(call: Call<User>, response: Response<User>) {
				//get some user data
			}
		})

Easiest way to convert it to a suspendable function is to wrap synchronous execute call to async Coroutine builder.

suspend fun getUserAsync(userName: String) = async(CommonPool) {
	gitHubApi.getUser(userName).execute()
}.await()

Now the retrofit call will be executed on one of the CommonPool threads and async method returns a Deferred interface which has a method await. This method is a suspending function.
Coroutines in Kotlin can only be called from other Coroutines. So now in the UI, you would use a launch to build a new Coroutine using UI context. In this coroutine we are consuming the one we built previously.

fab.setOnClickListener { view -> 
                        job = launch(UI) {
                              val user = getUserAsync(“someUser”) // suspension happens here
                              processUser(user)			
		}
}

In Java, almost everything asynchronous is using callbacks. And Kotlin offers a suspendCoroutines builder for creating a Coroutine from callbacks. So, we could use Kotlin's extension methods and create a generic method that turns any Call to a Coroutine.

suspend fun <T> Call<T>.await(): T {
	return suspendCoroutine { continuation ->
		this.enqueue(object : Callback<T> {
			override fun onFailure(call: Call<T>?, t: Throwable) {
				continuation.resumeWithException(t)
			}

			override fun onResponse(call: Call<T>?, response: Response<T>) {
				continuation.resume(response.body())
			}
		})
	}
}

Now the call in the UI is

fab.setOnClickListener { view ->
			job = launch(UI) {
                               val user = gitHubApi.getUser(“someUser”).await()
                               processUser(user)		
		}
}

No callbacks, HTTP request is executed asynchronously without blocking the Main thread. Nice!


Things that could be improved

Before trying out Kotlin's Coroutines I used C# async/await extensively and I have a feeling that some things are nicer to use in C#. Let's go over things that could be better.
No designated keyword for marking a suspension point

C# has await keyword which tells you what function is being awaited and where the function is going to be suspended. Kotlin doesn’t have anything similar. This makes it hard to spot the suspending point.

An example

fun somethingBlocking() = { Thread.sleep(1000) }

suspend fun somethingAsync() = run(CommonPool) { Thread.sleep(1000) } //simulate long running task

launch(UI) {
	someBlocking() //this will block the UI thread
	somethingAsync() //this will not
}

If you name your suspending functions with async suffix or prefix then this partially solves the problem.

Different ways of starting Coroutines

You can create coroutines with all these methods: async, run and launch. Yes, they return different objects, like Job and Deferred, but this is can be confusing.
In C#, an awaitable always returns a generic Task class.

Capturing context is confusing

The most common usage scenario for async methods is starting some long-running work on the main thread and using the result of async method back on the main thread. You have to launch a coroutine using Unconfined or UI context if you want to start it in the same Thread / Context of the caller. I like C# implementation better, you can configure any awaitable to capture the caller’s context. In such mode, awaitable if the context is captured, it will use it for posting the result to that context. This is also the default behavior, you don’t have to configure anything to have it.

You have to always supply a CoroutineContext

When building Coroutines with async or run, you always have to specify a CoroutineContext.
Why not provide a default implementation. If CoroutineContext is omitted, use the default CommonPool context?


in the end, even though it is still an experimental addition to the language, I'm really excited to see this in the JVM world.