Async/Await series


#21

I’m a fan of Kotlin’s coroutines. They’re similar in a lot of ways, though there are some important differences I’ve brought up before:


#22

I second everything you wrote there. To be honest, after working with Kotlin coroutines I just wish every language would build its nonblocking implementation on top of that kind of mechanism. It really feels like a much-needed breakthrough after all the callbacks/futures/RX jungle. I’m not sure about how performance compares to other approaches, though.


#23

I also concur with the sentiment that Kotlin coroutines have a lot of ergonomic and intuitive advantages. I’ve personally used Kotlin’s Coroutine library for an Android UI and it’s both more ergonomic and much more efficient than alternative solutions. The system’s flexibility to support the front-end API’s reminiscent of other languages like Go’s switch or async/await while not causing substantial increases in memory usage feels very optimal.


#24

W.r.t. Kotlin experience reports, can we be explicit about what the alternatives being compared against are? C# async/await? Go/Haskell green threads? Algebraic effects? I have no trouble believing it’s much superior to callbacks, but that’s presumably true of most options. :slight_smile:


#25

I haven’t looked closely at kotlin but it seemed analogous to the fact that kotlin has TCP preserving closures, which we don’t have & which is very difficult to integrate with ownership/borrowing and our absence of a runtime.


#26

I compared Kotlin’s coroutines to Java futures and ReactiveX. I haven’t used an async/await framework before, so it’s hard to comment there. But KC implement async/await and, while that functionality has its uses, the syntax is much more verbose than vanilla coroutines. The primary advantage of KC over everything else I tried is that it doesn’t obscure your logic with boilerplate and allows you to keep it ordered in the same way like it was blocking code, i.e. it allows you to lay out your code the way you want to, not the way the framework imposes on you. That’s hard to overestimate, really. Another advantage is that it integrates well with legacy code based on callbacks and futures. I used it in combination with Vert.x, which is based on futures. While a modest amount of glue was necessary, it primarily involved just calling .await() on a returned future and felt completely fluid.

If you know any other async frameworks that have the same qualities, I would be very interested to learn about them.


#27

What do Kotlin’s coroutines have to do with its TCP closures? The two don’t really interact, and even if they did they implement TCP without relying on the GC or a runtime (they just inline the closures)…


#28

Its closest relations are C#, Python, and Javascript’s async/await. They also allow your code to stay ordered the same way as blocking code, and integrate with existing callback and futures-based code.

The main difference with Kotlin coroutines, as far as I’m aware, is the presence of the await keyword, and the way you write the return type of the function. In C#, calling an async function gives you a future (Task<T>), which you then await to suspend and get its value:

async Task<int> AccessTheWebAsync()
{
    HttpClient client = new HttpClient();
    string page = await client.GetStringAsync("https://example.com");
    return await FurtherProcessing(page);
}

While Kotlin coroutines are much more syntactically similar to sync code (using a fake API to match the C# example):

suspend fun accessTheWeb(): int {
    val client = HttpClient()
    val page = client.getString("https://example.com")
    return furtherProcessing(page)
}

#29

I’m comparing KC to Goroutines, Java Futures, C# Tasks, RxJava and RxKotlin (Observable Patterns), though most of my work involves writing C for Cortex-M microcontrollers.

For instance, KC’s let me easily compose functions with timeouts which are common for communication protocols.

suspend fun sendRadioCmd(): Boolean {
    val radio = Radio()
    val timeout = 1000L

    return withTimeoutOrNull(timeout) {radio.sendCmd()} ?: false
}

This KC example is somewhat contrived, but in effect, it’s a simple operation where we’re referencing a radio device and then sending a command. If it doesn’t return within 1 second then we’re passed a null and we return false by default.

Kotlin drops this suspendable function into a anonymous class of a Finite State Machine, where each call to a suspendable function acts as a label for the FSM where it can be paused safely.

I will admit, this system is helped along by JetBrains’s IDEs as it will mark which of the functions you are calling are marked with the suspend keyword (in this case sendCmd() and withTimeoutOrNull()), but forcing coroutines to only be able to be called by other coroutines does help restrict some of the viral nature of the syntax, among other advantages.

I will also say that I am excited for the direction of Futures 0.2 and in particular the design space for async programming on embedded devices with the potential ability to pin generators to the stack (so I can stop hand coding so many state machines!). I see the Embedded WG has touched upon this on Wednesday already.


#30

HI,

I have start my own work on wanting to propose a tweak to the async/await pattern for typescript/emca/c#, I have been extensively using it in typescript and c# projects in function and object orientated approaches.

I would like to share my current experience, with you guys since you are in the early stages, may help you. As I would be interested, while I play catch up with your findings in entirety/proposals, that you may provide myself with any feedback, any insight you may have had or gain any insight from my document.

Rust post for the document:

async/await pattern, improvement and abstraction, tweak, at script level and type level support.