https://kotlinlang.org logo
#coroutines
Title
# coroutines
m

Martin Nordholts

06/08/2020, 6:46 AM
Hi, What is the idiomatic way to make suspend functions cross Java callback boundaries? This code
Copy code
suspend fun g(): String = "bar"
suspend fun f(mutableMap: MutableMap<String, String>) {
    mutableMap.computeIfAbsent("foo") {
        g()
    }
}
gives me
Suspension functions can be called only within coroutine body
compilation errror on the
g()
call. The only solution I can come up with is to re-implement
computeIfAbsent
in Kotlin and make the
fun
inline
, but that does not seem like an elegant, idiomatic solution. What is the proper solution to this problem?
o

octylFractal

06/08/2020, 6:48 AM
I don't think there really is one, that's just how it is.
computeIfAbsent
can do all sorts of locking and stuff that doesn't work with the
suspend
mechanism
if you must call a
suspend
function, you can use
runBlocking
, but there's no way to cross the java boundary
m

Martin Nordholts

06/08/2020, 6:52 AM
computeIfAbsent
is a regular function with simple logic that does not involve and locks or other such things: https://docs.oracle.com/javase/8/docs/api/java/util/Map.html#computeIfAbsent-K-java.util.function.Function- And wrapping in
runBlocking
does not get rid of the compilation error.
o

octylFractal

06/08/2020, 6:52 AM
it doesn't in the base implementation, but it can in overrides
see e.g.
ConcurrentHashMap
and I'd be surprised about that - what's the error?
m

Martin Nordholts

06/08/2020, 6:53 AM
ok, runBlocking within the mappingFunction helped. Thanks for that insight, I didn’t think of that!
o

octylFractal

06/08/2020, 6:54 AM
do note that it will be breaking the structured concurrency there, but it's impossible to cross that boundary because of how coroutines are implemented. it will get better eventually once project loom lands in the JVM
m

Martin Nordholts

06/08/2020, 6:55 AM
I suppose that if I wrap the whole thing in
withContext(<http://Dispatchers.IO|Dispatchers.IO>)
it is not that big of a deal to use
runBlocking
o

octylFractal

06/08/2020, 6:56 AM
yes, it'll always be blocking
m

Martin Nordholts

06/08/2020, 6:56 AM
And you’re right about
ConcurrentHashMap
in the general case of course. Although in my case that is not used
o

octylFractal

06/08/2020, 6:56 AM
mhm -- if you know the types going into that method, then by all means optimize for your case
d

Dominaezzz

06/08/2020, 6:57 AM
Even better,
runInterruptible(<http://Dispatchers.IO|Dispatchers.IO>) {  }
then cancellation will work across the java boundary.
✔️ 1
o

octylFractal

06/08/2020, 6:57 AM
ah, I'd forgotten about that new feature
e

elizarov

06/08/2020, 8:36 AM
If you don’t use
ConcurrentHashMap
then just replace Javas
computeIfAbsent
with Kotlin’s inline
getOrPut
👍 1
🙏 1
1
8 Views