Gotcha with “async” in Kotlin suspend function


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.


Leave a Reply

Your email address will not be published.