Hash

beginner

The Hash typeclass abstracts the ability to compute the hash of any object.
It can be considered the typeclass equivalent of Java’s Object#hashcode and Kotlin’s Any#hashCode.

A hash function is a mapping of arbitrary data (F) to an output set of fixed size (Int). The result, a hash value, is most commonly used in collections like HashTable as a lookup value.

import arrow.instances.*

fun main(args: Array<String>) {
  //sampleStart
  // Enable the extension functions inside Hash using run
  val result = String.hash().run { "1".hash() }
  //sampleEnd
  println(result)
}

Main Combinators

F.hash

Computes a hash of an instance of F.

fun F.hash(): Int

import arrow.instances.*

fun main(args: Array<String>) {
  //sampleStart
  // Enable the extension functions inside Hash using run
  val result = String.hash().run { "MyString".hash() }
  //sampleEnd
  println(result)
}

Laws

Arrow provides HashLaws in the form of test cases for internal verification of lawful instances and third party apps creating their own Hash instances.

Creating your own Hash instances

Hash contains a special instance that delegates to Kotlin’s Any?.hashCode() function in all cases. This may be sufficient for most use cases, but will fail for data types that contain functions, typeclasses or non-data classes. It also might make more sense to provide your own instance in for some cases, for example when there is already a unique property on an object. Hash has a constructor to create a Hash instance from any function (F) -> Int.

import arrow.typeclasses.Hash

data class User(val id: String, val name: String)
val user = User("MyId", "MyName")

fun main(args: Array<String>) {
  //sampleStart
  // This is fine
  val result = Hash.any().run { user.hash() }
  //sampleEnd
  println(result)
}
import arrow.typeclasses.Hash

data class User(val id: String, val name: String)
val user = User("MyId", "MyName")

fun main(args: Array<String>) {
  //sampleStart  
  // This might be better because id usually is a unique value in itself
  val userHash = Hash<User> { u -> u.id.hashCode() }
  val result = userHash.run { user.hash() }
  //sampleEnd
  println(result)
}
import arrow.core.*
import arrow.typeclasses.Hash

fun main(args: Array<String>) {
  //sampleStart
  // This will return false because it's not evaluated for hashing
  val result = Hash.any().run { Eval.later { 1 }.hash() == Eval.later { 1 }.hash() }
  //sampleEnd
  println(result)
}
import arrow.typeclasses.Hash

fun main(args: Array<String>) {
  //sampleStart
  // using invoke constructor
  val stringHash = Hash<String> { a -> a.hashCode() }
  val result = stringHash.run { "MyString".hash() }
  //sampleEnd
  println(result)
}

See Deriving and creating custom typeclass to provide your own Hash instances for custom datatypes.

Data types

Module Data types
arrow.core Either, Id, Option, Try, Tuple10, Tuple2, Tuple3, Tuple4, Tuple5, Tuple6, Tuple7, Tuple8, Tuple9
arrow.data Coproduct, Sum, Ior, ListK, MapK, NonEmptyList, SequenceK, SetK, Validated
arrow.typeclasses Const

Hierarchy