Can we match Any to a generic type? [Scala 2.8]
Asked Answered
F

2

5

Please point me to correct link if this has been answered before.

I have this code:

def getResult(a:Any):Any = a

def getAnswer[T](i:Int) = {
  val result = getResult(i)
  result match {
    case t:T => Some(t)
    case _ => None
  }
}

This gives me a unchecked warning and everything matches to T. For instance, when I do getAnswer[Int](2), I get Some(2) (as expected). However, if I do getAnswer[String](2), I also get Some(2) which is not expected (I need None).

Is there any way to work around type erasure and somehow get getAnswer to work correctly (i.e., return Some(result) if and only if the result is of type T)?

Thanks in advance.

Famulus answered 1/2, 2011 at 6:8 Comment(0)
E
7
def getAnswer[T](i:Any)(implicit m:Manifest[T]) = i match {
    case t:Int if m.erasure == classOf[Int] => Some(t)
    case t:Double if m.erasure == classOf[Double] => Some(t)
    //... other Primitives  
    case t if m.erasure.isInstance(t) => Some(t) //this matches AnyRefs
    case _ => None
}

As Alexey wrote, you have some trouble with primitives. The technique used in the Scala sources in such cases involves always separate matches for every single primitive type, so I guess there is no way around.

Evangel answered 1/2, 2011 at 7:40 Comment(2)
Thanks for your answer on how to handle primitives. Alexey's answer is also good.Famulus
I selected your answer as correct because it can handle primitive types. Once again, thanks for the code.Famulus
J
5

This works with some limitations (T must be a class and not a primitive type; if T is generic, parameters are ignored).

def getAnswer[T](i:AnyRef)(implicit m:ClassManifest[T]) = {
  val result = getResult(i)
  if (result.getClass == m.erasure) Some(result.asInstanceOf[T]) else None
}

> getAnswer[java.lang.Integer](2.asInstanceOf[AnyRef])
res4: Option[java.lang.Integer] = Some(2)

getAnswer[String](2.asInstanceOf[AnyRef])
res1: Option[String] = None
Janeejaneen answered 1/2, 2011 at 7:4 Comment(1)
We need to modify getResult to also return AnyRef. In my case, T is always a class or object and never a primitive type, so this may just work for me. I will check and revert.Famulus

© 2022 - 2024 — McMap. All rights reserved.