Hello everyone. I was quite surprised that the fol...
# getting-started
e
Hello everyone. I was quite surprised that the following code doesn’t get compiled
Copy code
val map = mutableMapOf("key1" to 1)
map["key1"] += 2
Why Is it not possible to use increment in such a way?
👀 3
h
map["key1"]
gives you an instance of
Int
, which is immutable. You can't assign a new value to an
Int
.
e
😭
r
for it to work, you would need to have implemented
Int?.plusAssign(Int)
because it does not desugar into
map.get(a) = map.get(a) + b
but into
map.get(a).plusAssign(b)
h
Oh my. I hadn't even thought about nullability
 đŸ€Š
r
and yes,
get(a)
returns nullable, so that's another issue there 😛
u
You could do
m.compute("key1") { _, i -> i?.let { it + 1 } }
Or simpler,
m.computeIfPresent("key1") { _, i -> i + 1 }
e
yeah, seems like this is the most clean solution @Ulrik Rasmussen btw, Swift allows such a code
Copy code
map["key1"]! += 2
u
I don't know Swift, but it probably has a more baked in notion of maps. In Kotlin,
map[k]
is just sugar for
map.get(k)
t
Re Swift, I don't think it's the baked in nature of maps, it's that maps are structs in Swift. So the swift analog to OP's query actually would fail in Swift as well. In Swift, val becomes let (simplisitically) speaking, which would mean the struct was immutable. But once it was a var, it would be inherently mutable and would then work
e
if there were an API like
Copy code
fun <K, V> MutableMap<K, V>.findEntry(key: Key): MutableMap.MutableEntry<K, V>?
then you could
Copy code
m.findEntry("key1")?.let { it.setValue(it.value + 2) }
but sadly there is no such API
u
Something like this can be obtained via lenses though: https://arrow-kt.io/docs/optics/at/
m
Something else you could do:
Copy code
fun <K, V> MutableMap<K, V>.replace(key: K, value: (V) -> V) =
    compute(key) { _, old -> if (old == null) null else value(old) }

val map = mutableMapOf("a" to 42)
map.replace("a") { it + 1 }
println(map)
e
computeIfPresent as mentioned earlier would be better than compute since you're ignoring the absent case
m
Yes, correct. I‘d still define an extension function to get rid of the unused function parameter.
Copy code
fun <K, V> MutableMap<K, V>.replace(key: K, value: (V) -> V) =
    computeIfPresent(key) { _, old -> value(old) }

val map = mutableMapOf("a" to 42)
map.replace("a") { it + 1 }