Kotlin Async Gotcha

Today I was hacking on a project with Ktor, and wanting to execute two operations in parallel, which can be done using the async function available on a CoroutineContext:

suspend fun getRoadmapAndProjects(roadmapId: UUID): RoadmapAndProjects? {
    val roadmapD = async { dao.getRoadmap(roadmapId) }
    val projectsD = async { dao.getProjectsForRoadmap(roadmapId) }
    val roadmap = roadmapD.await()
    if (roadmap!= null) {
        val projects = projectsD.await()
        return RoadmapAndProjects(roadmap=roadmap, projects=projects)
    } else {
        return null
    }
}

But the compiler highlights the async calls and shows me this error:

Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public fun <T> CoroutineScope.async(context: CoroutineContext = ..., start: CoroutineStart = ..., block: suspend CoroutineScope.() → TypeVariable(T)): Deferred<TypeVariable(T)> defined in kotlinx.coroutines

As far as I can tell, it’s saying that the type of the block that I’m passing to async doesn’t conform to the type definition available on the context. As far as I could tell, I was doing just what the documentation said. I didn’t have the power to figure this one out for myself, so I turned to my co-worker, Amanda.

She poked, prodded, and fiddled, finally wrapping my code in a call to withContext, and voila! All the errors went away:

suspend fun getRoadmapAndProjects(roadmapId: UUID): RoadmapAndProjects? = withContext(Dispatchers.IO) {
    val roadmapD = async { dao.getRoadmap(roadmapId) }
    val projectsD = async { dao.getProjectsForRoadmap(roadmapId) }
    val roadmap = roadmapD.await()
    if (roadmap!= null) {
        val projects = projectsD.await()
        return@withContext RoadmapAndProjects(roadmap=roadmap, projects=projects)
    } else {
        return@withContext null
    }
}

Notice how I wrapped the whole function body in a call to withContext(Dispatchers.IO)? I don’t know enough about Kotlin or its coroutines library to understand exactly why this made my compiler errors go away. If you know, I’d love to hear about it in the comments.

2 comments on “Kotlin Async Gotcha

  1. I got the same error, but i think i understand 🙂 (just started my Kotlin journey )

    The async function def is defined as a ext method against coroutineScope thus can only be called on a coroutineScope object.

    as ‘withContext { … }’ is a ‘Receiver Function Type’ suspend CoroutineScope.() -> T

    when the withContext { val roadmapD = *this*.async … } closure is called, ‘this’ is a CoroutineScope object and ‘CoroutineScope.async method is available to be called.

    In my code im using ‘coroutineScope { … }’ for the same purpose

    1. Thanks for commenting!

Leave a Comment

Your email address will not be published. Required fields are marked *