https://kotlinlang.org logo
Title
c

Colton Idle

05/12/2023, 6:08 AM
Okay, I've been staring at this too long. Am I missing something basic here. Why can't I do
myMap.value[MyType.A] = listOf(MyThing(1), MyThing(2))
myMap.value[MyType.B] = listOf(MyThing(3), MyThing(4))
myMap.value[MyType.C] = listOf(MyThing(5), MyThing(6))
with a map defined of
val myMap = _MutableStateFlow_<Map<MyType, List<MyThing>>>(_emptyMap_())
c

Chris Lee

05/12/2023, 6:37 AM
That .value doesn’t seem right, though am unfamiliar with that map impl.
v

Vampire

05/12/2023, 6:38 AM
I'd say
Map
vs.
MutableMap
c

Colton Idle

05/12/2023, 7:10 AM
🤦
Looks like my eyesw kept going to MutableStateFlow and thinking that it should be fine to be mutated.
I wonder if MutableStateFlow with a MutableMap is fine?
w

Wout Werkman

05/12/2023, 9:58 AM
I would not recommend using MutableMap inside MutableStateFlow. Whoever observes the flow will not observe changes in the MutableMap. While in theory it's possible to design your flows with this in mind, nesting mutable data is generally considered a bug magnet.
In the example you showed here, the value might be updated in between the insertions you make into the map. This could make that: 1. You insert the
MyType.A
entry into one map. 2.
myMap.value
get's updated from another thread 3. You insert the
MyType.B
and
MyType.C
entries into the new map 4. The new map is now missing the
MyType.A
entry
You could achieve the same semantics without race conditions as follows:
val myMap = MutableStateFlow<Map<MyType, List<MyThing>>>(emptyMap())
myMap.update { oldValue ->
  oldValue + mapOf(
    MyType.A to listOf(MyThing(1), MyThing(2)),
    MyType.B to listOf(MyThing(3), MyThing(4)),
    MyType.C to listOf(MyThing(5), MyThing(6)),
  )
}
c

Colton Idle

05/12/2023, 12:57 PM
hm. cant seem to get something like that to compile. i'll keep trying. maybe some extension function isn't making it's way it. one last question though. is there a way to be able to set the data in this sort of way? Where I can udpate a specific item in the map vs adding to the map? myMap.value[MyType.A] = listOf(MyThing(1), MyThing(2))
c

Chris Lee

05/12/2023, 1:14 PM
yes, mutable maps support the [] operator and assignment. Won’t work if map is not mutable.
w

Wout Werkman

05/12/2023, 1:46 PM
No, it won't work on immutable maps. It's always recommended to use
update
myMap.update { it + (MyType.A to listOf(MyThing(1), MyThing(2)) }
You can wrap it in a utility function:
operator fun MutableStateFlow<Map<MyType, List<MyThing>>>.set(key: MyType, value: List<MyThing>): Unit = update { it + (key to value) }

myMap[MyType.A] = listOf(MyThing(1), MyThing(2))
f

Francesc

05/12/2023, 3:49 PM
if you use a mutable map or list on the state flow it won't emit when you make changes to it because, internally, the state flow is comparing it against the current value, which is the same, so nothing gets emitted.