Hi!
I’m using coroutines to load items from a data repository. Let’s imagine I’m talking about fetching pizzas.
The repository first checks a cache, which will hand back a (nullable) List<Pizza>?
. Arguably it could instead return an emptyListOf<Pizza>()
but that’s not the case here.) If that list is null
, it instead fetches the pizzas from an API, which is guaranteed to return a (non-nullable) List<Pizza>
. Here’s how I thought I’d accomplish just that:
class PizzasRepository {
fun load(): Deferred<List<Pizza>> = async {
val cache = loadFromCache()
if (cache != null) {
return@async cache
}
return@async lostFromApi().await()
}
private fun loadFromCache(): List<Pizza>? = cachedPizzas
private fun loadFromApi(): List<Pizza> = async { listOf(Pizza()) }
}
However, this code doesn’t compile, with the following error:
Type inference failed. Expected type mismatch: inferred type is Deferred<List?> but Deferred<List> was expected
The problematic line is the return@async cache
line, but I was under the impression that the compiler would be able to smart cast that to a List<Pizza>
, because the val
is checked above and is final.
Appending “bang bang” – with or without Jessie J, Ariana Grande & Nicki Minaj – the code compiles, but the linter tells me that the bangs are unnecessary:
fun load(): Deferred<List<Pizza>> = async {
val cache = loadFromCache()
if (cache != null) {
// Unnecessary non-null assertion (!!) on a non-null receiver of type List<Pizza>
return@async cache!!
}
return@async loadFromApi().await()
}
It might just be that I’m missing something crucial here, or there’s something not entirely right about coroutines and smart casts working together. Coroutines are, after all, in an experimental stage.
Any thoughts?
Thanks!