I want to create a hashmap to store parameters names and their values. The parameters however are with different types. I could use HashMap[String, Any], but I wouldn't know which types they are later on. Is there anyway I can recovery the type information? Or is there any better way to store pair?
-
possible duplicate of [How do I get around type erasure on Scala? Or, why can't I get the type parameter of my collections?](http://stackoverflow.com/questions/1094173/how-do-i-get-around-type-erasure-on-scala-or-why-cant-i-get-the-type-parameter) – Daniel C. Sobral Nov 30 '10 at 10:38
-
Were any of these answers useful to you? If not, do you have any feedback that would help us target your requirements better? – Aaron Novstrup Dec 04 '10 at 02:09
-
well, none of them really solved my problem. I was told (offline) by some people there is no elegant solution. I changed my design later to avoid such a problem... – user398384 Dec 07 '10 at 20:18
-
What about using Daniel's solution, and changing `get` to return a pair of the key's value and the value's Manifest? – Jean-Philippe Pellet Mar 31 '11 at 06:36
3 Answers
Do you want access to the static type information, or the dynamic type information? If you're after the former, you can use typed keys. Something along these lines should work:
final class Key[T]
object Registry {
private var backingMap: Map[Key[_], _] = Map.empty
def put[T](k: Key[T], v: T) = backingMap += (k -> v)
def get[T](k: Key[T]): Option[T] = backingMap get k map (_.asInstanceOf[T])
}
scala> val strKey = new Key[String]
strKey: Key[String] = Key@31028a
scala> val intKey = new Key[Int]
intKey: Key[Int] = Key@7ae77ca4
scala> Registry.put(strKey, "asdf")
scala> Registry.get(strKey)
res0: Option[String] = Some(asdf)
scala> Registry.put(intKey, "asdf")
<console>:10: error: type mismatch;
found : Key[Int]
required: Key[Any]
Registry.put(intKey, "asdf")
Alternately, you can use untyped keys and store the type information in the Map using manifests (as Daniel suggested):
class Registry[K] {
import scala.reflect.Manifest
private var _map= Map.empty[K,(Manifest[_], Any)]
def put[T](key: K, item: T)(implicit m: Manifest[T]) {
_map += (key -> (m, item))
}
def get[T](key:K)(implicit m : Manifest[T]): Option[T] = {
for ((om, v) <- _map get key if om <:< m)
yield v.asInstanceOf[T]
}
}
The latter approach has the advantage that you can use anything as a key, and you don't have to pass the original typed key objects around. However, it has the drawback that you must specify the value type when you call the get
method. If you specify the wrong type you'll get None
just as if the key is not in the Registry at all, whereas with typed keys you're guaranteed to get any value associated with a key.

- 1
- 1

- 20,967
- 7
- 70
- 108
See this, which implements exactly what you ask for.

- 1
- 1

- 295,120
- 86
- 501
- 681
-
Nice! I simplified your implementation somewhat in my answer and attempted to explain the differences between the typed key approach and the stored manifest approach. – Aaron Novstrup Nov 30 '10 at 23:13