I have a class 'Foo' (not under my control) which I wish to use as a key in a kotlin (java) hashmap. The problem is that the 'equals' method for 'Foo' does value equivalence. For my situation value equivalence is too loose. I need object equivalence.
What are the ways to force force the use of object equivalence on the keys?
I am thinking something like...
data class Foo(val prop: String)
data class Bar(val prop: String)
fun main() {
val fooMap = mutableMapOf<Any, Bar>()
val fooA = Foo("common value")
val fooB = Foo("common value")
fooMap[fooA] = Bar("different A")
fooMap[fooB] = Bar("different B")
println("${fooMap.keys} ${fooMap.values}")
}
This results in a fooMap with only one entry, when I expect two.
[Foo(prop=common value)] [Bar(prop=different B)]
CodePudding user response:
Consider using IdentityHashMap
- it is the same map, but which compares only references of the keys.
Also note, to effectively use regular HashMap, the key class must respect not only equals
, but also hashCode
.
CodePudding user response:
I will be using @AterLux answer but I am posting what I had been using for comments.
data class Identity<T>(private val delegate: T) {
override fun equals(other: Any?): Boolean {
return delegate === other
}
}
fun <K,V> mutableIdentityMapOf(): MutableMap<Identity<K>,V> {
return mutableMapOf()
}
data class Foo(val prop: String)
data class Bar(val prop: String)
fun main() {
val fooMap = mutableIdentityMapOf<Foo, Bar>()
val fooA = Foo("common value")
val fooB = Foo("common value")
fooMap[Identity(fooA)] = Bar("different A")
fooMap[Identity(fooB)] = Bar("different B")
println("${fooMap.keys} ${fooMap.values}")
}
CodePudding user response:
For your specific case and when targeting JVM, IdentityHashMap
is probably the best choice, as suggested by @AterLux .
If we need multiplatform solution or we have a more generic case of changing the equals()
logic of a third party class, we can simply use our own wrapper as a key:
data class FooKey(val foo: Foo) {
override fun equals(other: Any?) = foo === (other as? FooKey)?.foo
}
fun main() {
val fooMap = mutableMapOf<FooKey, Bar>()
val fooA = Foo("common value")
val fooB = Foo("common value")
fooMap[FooKey(fooA)] = Bar("different A")
fooMap[FooKey(fooB)] = Bar("different B")
println("${fooMap.keys} ${fooMap.values}")
}