kotlinreferenceequalitydata-classmutablemap

Kotlin modifying dataclass object key from map changes the reference after modifying variable


I have a MutableMap that its keys are objects from a DataClass (User dataclass), and the values are arrays from other Dataclass (Dog dataclass). If i have a variable with a User object, and i put it in the MutableMap and i test if the map contains the User, it says that is true. But after putting the user in the MutableMap if i change one of the attributes of the User object using the variable that holds the User object, the Map says that it doesnt contains the user object.

This is an example

data class User(
    var name: String,
    var project: String,
)

data class Dog(
    var kind: String
)


fun main(args: Array<String>) {
    var mapUserDogs: MutableMap<User, MutableList<Dog>> = mutableMapOf()
    var userSelected = User("name2", "P2")

    mapUserDogs.put(
        User("name1", "P1"),
        mutableListOf(Dog("R1"), Dog("R2"))
    )

    mapUserDogs.put(
        userSelected,
        mutableListOf(Dog("R21"), Dog("R31"))
    )

    println(userSelected)
    println(mapUserDogs.keys.toString())
    println(mapUserDogs.contains(userSelected))
    println(mapUserDogs.values.toString())
    println("\n")

    userSelected.name = "Name3"

    println(userSelected)
    println(mapUserDogs.keys.toString())
    println(mapUserDogs.contains(userSelected))
    println(mapUserDogs.values.toString())
}

The prints statements show this:

User(name=name2, project=P2)
[User(name=name1, project=P1), User(name=name2, project=P2)]
true
[[Dog(kind=R1), Dog(kind=R2)], [Dog(kind=R21), Dog(kind=R31)]]


User(name=Name3, project=P2)
[User(name=name1, project=P1), User(name=Name3, project=P2)]
false
[[Dog(kind=R1), Dog(kind=R2)], [Dog(kind=R21), Dog(kind=R31)]]

Process finished with exit code 0

But it doesn't make sense. Why the map says that it doesn't contains the user object if its clear that it still holds the reference to it after being modified?

User(name=Name3, project=P2)
[User(name=name1, project=P1), User(name=Name3, project=P2)]

The user in the keys collection was also changed when i modified the userSelected variable, so now the object has it attribute name as "Name3" in both the variable and in the Map keys, but it still says that it doesnt contains it.

What can i do so that i can change the attributes in the userSelected object and the Map still return true when using the "contains" method?. And doing the same process in reverse shows the same. If i get from the map the user and i modify it, the userVariable is also modified but if i later test if the map contains the userVariable, it says false.


Solution

  • What can i do so that i can change the attributes in the userSelected object and the Map still return true when using the "contains" method?

    There is nothing you can do that preserves both your ability to look up the entry in the map and your ability to modify the key.

    Make your data class immutable (val instead of var, etc.), and when you need to change a mapping, remove the old key and put in the new key. That's really the only useful thing you can do.