Best replacement for java Objects.hash()

Yes, java has Objects.hash(...), but I’ve always hated that it allocates a new array and boxes all the parameters. There should really be a simple Kotlin alternative that doesn’t have all that overhead.

If you have fields a, b, c, d, and e, what’s the best way to combine their hashes in kotlin?

This works:

fun hashCode() = 
    (((a.hashCode()*31 + b.hashCode)*31 + c.hashCode())*31 + d.hashCode())*31 + e.hashCode()` 

… but who wants to count all those brackets?

I’m currently doing this:

fun hashCode() = a.hashCode()
    .times(31).plus(b.hashCode())
    .times(31).plus(c.hashCode())
    .times(31).plus(d.hashCode())
    .times(31).plus(e.hashCode())

That’s pretty fun.

Does anyone have a better way?

1 Like

At this moment I don’t think that there is any better solution than yours :slight_smile: Although a potential approach would be to use an inline function:

inline fun hashCodeOf(a: Any?, b: Any?, c: Any?): Int = a.hashCode()
	.times(31).plus(b.hashCode())
	.times(31).plus(c.hashCode())

private class MyDataClass(val a: Int, val b: Long, val c: Double) {
	override fun hashCode() = hashCodeOf(a, b, c)
	
	override fun equals(other: Any?) = this === other || other is MyDataClass
		&& a == other.a
		&& b == other.b
		&& c.compareTo(other.c) == 0
}

Unfortunatelly, even after inlining a boxing issue still remains. This could probably be optimized if an official ticket was posted :wink:

An improvement on the above:

inline fun hashAll(vararg vals: Any?): Int {
    var res = 0
    for (v in vals) {
        res += v.hashCode()
        res *= 31
    }
    return res
}

IIUC this will not create any intermediate array, because of the inlining.

It does create an array even if it is inlined, it has the same problem as Objects.hash(...)

2 Likes

Forgive me if I’m pointing out the obvious, but are you aware that a kotlin data class creates equals, hashCode, and toString for you?

Also, if I’m creating a hashcode function for something other than a data class that needs it, I usually go for speed (and less prone to manual mistakes) over beauty, so I personally prefer alt + insert generate “equals() and hashCode()”

1 Like

Yeap, data classe are a big beauty, but there are situations, like inheritance, where it simply won’t work with data classes alone.

2 Likes