1

I want to be able to have a map implementation of type [String,Any] in which i can store objects of different classes then i want to be able to do

import app.User;
....
usr = map.getAs("user",User)// with usr being an object of Class/Object User. If user is not of that type it throws an exception.

where user was previously stored in the map.

Is this possible?

I can even be a standalone method e.g

 usr = getAs(map,"user",User)

Thanks

AdiFatLady
  • 368
  • 1
  • 6
  • 18

3 Answers3

5

You can use ClassTag. I don't have a lot of experience with it, but something like that should work:

def getAs[T: ClassTag](m: Map[String, Any], key: String): T = 
  m(key).asInstanceOf[T]

Usage:

val map = Map[String, Any]("one" -> 1, "hello"-> "world")
getAs[String](map, "hello")
res1: String = world

I let you deal with the exception, you can simply wrap the asInstanceOf in a Try, or whichever strategy you prefer. I also recommend changing the return type to Option[T].

vptheron
  • 7,426
  • 25
  • 34
1

Thanks vptheron. That definitely works. I took your advice and did it using Option[T] and used matching instead.

def getAsOption[T: ClassTag](m: Map[String, Any], key: String): Option[T] =
m.get(key) match {
    case x : Option[T] => x
    case _ => None
}   

I wanted a mechanism to pass random stuff in the play framework and this looks like a good solution for me though the purists wont like it.

AdiFatLady
  • 368
  • 1
  • 6
  • 18
  • Using `getAsOption[Int](Map[String, Any]("1" -> "hello"), "1")` yields `Option[Int] = Some(hello)` in my REPL. This is of course nonsense and will throw exceptions when you use operations on that Option, like `get`. In @vptheron 's answer the exception is directly thrown. – Kigyo Aug 26 '14 at 02:11
1

I think using TypeTag will do better job unless you will never cast the values into generic types.

import scala.reflect.runtime.universe._

trait Typed[A] {
  val value: A
  implicit val ttag: TypeTag[A]
}

def cast[A, B: TypeTag](v: Typed[A]): Option[B] = {
  val tA = typeOf[A](v.ttag)
  val tB = typeOf[B]
  def vB = v.value.asInstanceOf[B]
  if (tA <:< tB) Some(vB) else None
}

def getTyped[A, B, C: TypeTag](map: Map[A, Typed[B]], key: A): Option[C] = {
  map get key flatMap cast[B, C]
}
Ryoichiro Oka
  • 1,949
  • 2
  • 13
  • 20