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

okarm

09/01/2020, 3:28 PM
Maybe not related to coroutines, but that's where I found it: Can anybody explain to me why the following code works? https://pl.kotl.in/O8wu8VKSE In essence the code sets an instance of type
B
as a value of
StateFlow<A>
. I would not expect that to be possible. The code not only compiles, it actually runs in the Playground without a run-time exception.
o

octylFractal

09/01/2020, 5:10 PM
because you forced an unsafe cast and you're never type checking, so the generic doesn't come into play (generic type erasure)
if you did
val a = flow.value
I would expect an exception as kotlin should introduce a cast there
and indeed, that's what happens
o

okarm

09/01/2020, 5:31 PM
Well, when the very same implementation is used with a LiveData receiver (casting LiveData to MutableLiveData as opposed to casting StateFlow to MutableStateFlow), compiler doesn't allow posting
B
to
LiveData<A>
. But it it has no problem setting
B
as value of
StateFlow<A>
w

wasyl

09/01/2020, 7:11 PM
I suppose it is a bit surprising that
MutableStateFlow
doesn’t perform any checks when setting value of a wrong type 🤔
o

octylFractal

09/01/2020, 7:55 PM
it shouldn't have to, don't make an unsafe cast!
additionally, it can't -- it has no type information, that's how erasure works
o

okarm

09/01/2020, 8:14 PM
@octylFractal If it can't then how is it possible that with LiveData it correctly infers an attempt to set a value of incompatible type, refusing to even compile? I have no problem with the behavior, but I dn't know why it's inconsistent.
And I just realized there's a difference between the two.
public abstract class LiveData<T>
vs
public interface StateFlow<out T>
- There's no out-projection in LiveData
o

octylFractal

09/01/2020, 8:39 PM
isn't that just because
LiveData
is a Java class, not a Kotlin one?
1
hmm, I see what you mean now
I suspect it is due to that inconsistency with the type parameters --
out T
allows such things as:
Copy code
interface Source<out T> {
    fun nextT(): T
}

fun demo(strs: Source<String>) {
    val objects: Source<Any> = strs // This is OK, since T is an out-parameter
    // ...
}
so kotlinc is able to infer
StateFlow<Any>
from the
flow
and allow the unsafe set
this is why
MutableStateFlow
doesn't declare
out T
, but just
T
-- since it prevents input from being promoted to
Any
☝🏻 1
a

araqnid

09/01/2020, 9:36 PM
That’s why MutableList etc are invariate compared to List in general
6 Views