Hi, I'm running into this error when trying to use...
# announcements
d
Hi, I'm running into this error when trying to use
async
Copy code
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
I'm not sure how much I can pare down my example, because it seems pretty specific to what I'm trying to do. Here's essentially the function
Copy code
suspend fun getTile(params: SomeType): GetTileResponse {
        val cached = tileCache.get(params)
        if (cached != null) {
            return GetTileResponse.Available(cached)
        }

        val request = GetTileRequest(params)

        val deferred = async {
            makeRemoteRequest()
            .map { convertIntoResponse(it) }
        }

        return GetTileResponse.Loading(deferred)
    }
If I ask kotlin to generate an implementation of async, I get something which seems to look very similar to the definition of async (https://kotlin.github.io/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/async.html)
Copy code
private fun async(block: suspend CoroutineScope.() -> Either<GetTileError, Bitmap>): Deferred<Either<GetTileError, Bitmap>> {
        TODO("Not yet implemented")
    }
a
What you are trying to do is against the grain of structured concurrency, which is why you are having trouble expressing the idea. Fire and forget concurrency as expressed by returning futures/deferreds is generally discouraged in favor of suspend functions that complete their work entirely before returning and do not leave background tasks running for callers to separately monitor.
d
I don't understand. I'm not trying to have fire and forget concurrency
I'm trying to express that an action may either return a result now, or a result or an error later
a
you are returning a deferred in
GetTileResponse.Loading
that may or may not be loaded yet. Generally you want a function like this to return the real value after loading is complete, and suspend until there is a result or error to report.
d
I'm trying to return either a deferred or a value
I use this in a render loop, and I need to handle differently the case where I get a value now and the case where I enqueue to handle the value later
a
be that as it may, you'll have a much easier time if you move that distinction to the caller instead of creating layers of returning Deferred. As for why you can't find
async
- you need a
CoroutineScope
for it to launch into.
d
Thank you.
How could I move the distinction to the caller?
a
one way would be to offer a way to peek the cache for the given params from this class and not call a suspend function to check it. If it returns null or some other sentinel, have the caller launch an async request to your cache layer.
Generally this sort of setup ends up involving the caching layer having a
CoroutineScope
to scope the work of performing data fetches that may be shared across deduped requests
d
That makes sense
a
so the suspending fetch operation ends up performing
.await
on a
Deferred
from the caching layer, but the
Deferred
doesn't escape to the final caller
the deferred is a job launched into the cache's scope, and its execution will outlive a cancelled single request since another caller might make the same request again later
1461 Views