I have an object with stores information about specific instances. For that, i would like to use a Map
, but as the keys are not by-reference (they aren\'t, rig
EDIT: Based on clarifications to the question, you can create your own Map implementation, and override elemEquals().
The original implementation (in HashMap)
protected def elemEquals(key1: A, key2: A): Boolean = (key1 == key2)
Change this to:
protected def elemEquals(key1: A, key2: A): Boolean = (key1 eq key2)
class MyHashMap[A <: AnyRef, B] extends scala.collection.mutable.HashMap[A, B] {
protected override def elemEquals(key1: A, key2: A): Boolean = (key1 eq key2)
}
Note that to use eq, you need to restrict the key to be an AnyRef, or do a match in the elemEquals() method.
case class Foo(i: Int)
val f1 = new Foo(1)
val f2 = new Foo(1)
val map = new MyHashMap[Foo, String]()
map += (f1 -> "f1")
map += (f2 -> "f2")
map.get(f1) // Some(f1)
map.get(f2) // Some(f2)
-- Original answer
Map works with hashCode() and equals(). Have you implemented equals() correctly in your obejcts? Note that in Scala, ==
gets translated to a call to equals()
. To get the same behaviour of ==
in Java, use the Scala operator eq
case class Foo(i: Int)
val f1 = new Foo(1)
val f2 = new Foo(1)
f1 == f2 // true
f1.equals(f2) // true
f1 eq f2 // false
val map = new MyHashMap (f1 -> "f1", f2 -> "f2")
map.get(f1) // Some("f2")
map.get(f2) // Some("f2")
Here, the case class implements equals() to be object equivalence, in this case:
f1.i == f1.i
You need to override equals() in your objects to include object equality, i.e something like:
override def equals(o: Any) = { o.asInstanceOf[AnyRef] eq this }
This should still work with the same hashCode().
You can also use IdentityHashMap together with scala.collection.JavaConversions.
Ah based on comment... You could use a wrapper that overrides equal to have reference semantics.
class EqWrap[T <: AnyRef](val value: T) {
override def hashCode() = if (value == null) 0 else value.hashCode
override def equals(a: Any) = a match {
case ref: EqWrap[_] => ref.value eq value
case _ => false
}
}
object EqWrap {
def apply[T <: AnyRef](t: T) = new EqWrap(t)
}
case class A(i: Int)
val x = A(0)
val y = A(0)
val map = Map[EqWrap[A], Int](EqWrap(x) -> 1)
val xx = map.get(EqWrap(x))
val yy = map.get(EqWrap(y))
//xx: Option[Int] = Some(1)
//yy: Option[Int] = None
Original answer (based on not understanding the question - I have to leave this so that the comment makes sense...)
Map already has this semantic (unless I don't understand your question).
scala> val x = A(0)
x: A = A(0)
scala> val y = A(0)
y: A = A(0)
scala> x == y
res0: Boolean = true // objects are equal
scala> x.hashCode
res1: Int = -2081655426
scala> y.hashCode
res2: Int = -2081655426 // same hash code
scala> x eq y
res3: Boolean = false // not the same object
scala> val map = Map(x -> 1)
map: scala.collection.immutable.Map[A,Int] = Map(A(0) -> 1)
scala> map(y)
res8: Int = 1 // return the mapping based on hash code and equal semantic