2

I have written a generic function to get a value from a HashMap[String, AnyVal]. This method returns a value from the name but also has a functionality to make sure it is of a specific type:

class Context {
  private var variables = HashMap[String, Any] ()

  def getVariable (name: String):Any = variables(name)
  def setVariable (name: String, value: Any) = variables += ((name, value))

  def getVariableOfType[T <: AnyVal] (name:String):T ={
    val v = variables(name)
    v match {
      case T => v.asInstanceOf[T]
      case _ => null.asInstanceOf[T]
    }
  }

}

The function getVariableOfType[T <: AnyVal] will not compile because it says "Cannot resolve symbol T" at the line case T => v.asInstanceOf[T]

Vogon Jeltz
  • 1,166
  • 1
  • 14
  • 31
  • To make it compile, you probably meant: `case something: T => v.asInstanceOf[T] /*or better just: something */`. Though it is not recommended, you should use [`TypeTag`](http://docs.scala-lang.org/overviews/reflection/typetags-manifests.html)s. – Gábor Bakos Aug 17 '15 at 09:01
  • @GáborBakos I am trying to match by type but I will try that thanks – Vogon Jeltz Aug 17 '15 at 09:03
  • 1
    In that case you definitely should use type tags. Otherwise -because of erasure- it will always go on the first `case`. – Gábor Bakos Aug 17 '15 at 09:08
  • 1
    Besides what @Gábor says which is why your solution doesn't work, the compiler error is because you're match is wrong. It should be: `v match { case _ : T => v.asInstanceOf[T]}`, otherwise the compiler tries to match `v` to an already defined value called `T`. – Chirlo Aug 17 '15 at 09:20
  • [This](http://stackoverflow.com/questions/12218641/scala-what-is-a-typetag-and-how-do-i-use-it) explains type tags even better than the official documentation. – Gábor Bakos Aug 17 '15 at 09:41

1 Answers1

6

Simply having case x: T => v.asInstanceOf[T] will match any type because of erasure. To really do the type checking you have to make a ClassTag available for T: [T <: AnyVal : ClassTag].

Here is a working definition of getVariableOfType:

import scala.reflect.ClassTag

def getVariableOfType[T <: AnyVal : ClassTag] (name:String):T ={
  val v = variables(name)
  v match {
    case x: T => x
    case _ => null.asInstanceOf[T]
  }
}

The downside is that ClassTag doesn't completely remove the issue of erasure. So requesting for example a Seq[Int], will actually match on every type of sequence (Seq[Double], Seq[String], etc.). In your example T is a subtype of AnyVal, so this won't be an issue.

Kolmar
  • 14,086
  • 1
  • 22
  • 25