https://kotlinlang.org logo
#getting-started
Title
# getting-started
e

evkaky

05/20/2021, 10:10 AM
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

hho

05/20/2021, 10:19 AM
map["key1"]
gives you an instance of
Int
, which is immutable. You can't assign a new value to an
Int
.
e

evkaky

05/20/2021, 10:21 AM
😭
r

Roukanken

05/20/2021, 10:30 AM
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

hho

05/20/2021, 10:33 AM
Oh my. I hadn't even thought about nullability… 🤦
r

Roukanken

05/20/2021, 10:33 AM
and yes,
get(a)
returns nullable, so that's another issue there 😛
u

Ulrik Rasmussen

05/20/2021, 11:44 AM
You could do
m.compute("key1") { _, i -> i?.let { it + 1 } }
Or simpler,
m.computeIfPresent("key1") { _, i -> i + 1 }
e

evkaky

05/20/2021, 11:47 AM
yeah, seems like this is the most clean solution @Ulrik Rasmussen btw, Swift allows such a code
Copy code
map["key1"]! += 2
u

Ulrik Rasmussen

05/20/2021, 11:48 AM
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

Travis Griggs

05/20/2021, 4:42 PM
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

ephemient

05/20/2021, 6:06 PM
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

Ulrik Rasmussen

05/21/2021, 6:38 AM
Something like this can be obtained via lenses though: https://arrow-kt.io/docs/optics/at/
m

Michael Böiers

05/21/2021, 2:58 PM
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

ephemient

05/21/2021, 3:22 PM
computeIfPresent as mentioned earlier would be better than compute since you're ignoring the absent case
m

Michael Böiers

05/21/2021, 3:30 PM
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 }