Hi, What is the idiomatic way to make suspend func...
# coroutines
m
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
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
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
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
ok, runBlocking within the mappingFunction helped. Thanks for that insight, I didn’t think of that!
o
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
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
yes, it'll always be blocking
m
And you’re right about
ConcurrentHashMap
in the general case of course. Although in my case that is not used
o
mhm -- if you know the types going into that method, then by all means optimize for your case
d
Even better,
runInterruptible(<http://Dispatchers.IO|Dispatchers.IO>) {  }
then cancellation will work across the java boundary.
✔️ 1
o
ah, I'd forgotten about that new feature
e
If you don’t use
ConcurrentHashMap
then just replace Javas
computeIfAbsent
with Kotlin’s inline
getOrPut
👍 1
🙏 1
1