I currently have a method and i want to remove the...
# coroutines
c
I currently have a method and i want to remove the runBlocking
Copy code
fun getThing(): Thing {
  val innerThing = runBlocking { otherThing.getThing() }
  return Thing(innerThing.foo)
}
I can instead pass a scope into getThing(), but it didn't work as I expected. i.e.
Copy code
fun getThing(scope: CoroutineScope): Thing {
  val innerThing = scope.launch { otherThing.getThing() }
  return Thing(innerThing.foo)
}
doesnt compile ^
m
yes. because launch returns a job: P try withContext instead with just suspend ?
c
scope.launch
returns a
Job
, while
runBlocking
returns the value of the lambda. They are not interchangeable.
scope.async { }
is closer to what you want, but you’ll need to call
.await()
to get the value, which is also a suspending function. In general, it’s going to be difficult to mix suspending and non-suspending code in any logically-useful way. The best you can do is set up callbacks for everything just like you would have to do in Java, and then coroutines then become not much different than working with standard Threads. It’s best to make everything suspending, and then only at the last possible moment tie everything in to the non-suspending world. For example, do this instead:
Copy code
suspend fun getThing(): Thing {
  val innerThing = otherThing.getThing()
  return Thing(innerThing.foo)
}
and then push back the responsibility for creating and managing the coroutine to somewhere else (i.e. the Android ViewModel`
Copy code
class MyViewModel : ViewModel() {
    val thingStateFlow = MutableStateFlow<Thing?>(null)
    fun loadAThing() {
        viewModelScope.launch { 
            thingStateFlow.value = getThing()
        }
    }
}
m
If you have
CoroutineScope
it means you are already in some coroutine. So, in my opinion, the best solution is mark
getThing
as
suspend
c
Thanks for teaching everyone. @Casey Brooks that mental model that you explained made a lot of sense. 🍻
m
If you use JVM you also can do something similar:
Copy code
val innerThingFuture = scope.async { otherThing.getThing() }.asCompletableFuture()
And deal with future in non-coroutine code.
👀 1