ayvango
ayvango

Reputation: 5977

How to dynamically cast a variable to Option

I'd like to cast variables dynamically to Option[T]. The semantic is: if variable x matches T type, then cast should return Some(x) and it should return None otherwise. Using single map invocation is much cleaner than using isInstanceOf[T] accompanying asInstanceOf[T] or building monstrous case switches.

I had tried simple code below

object OptionCast {
  def apply[T](source : Any) : Option[T] = source match {
    case s : T => Some(s)
    case _ => None
  }
}

but it ignores types actually: OptionCast[Int]("some").map(_ + 2) gives me type error.

How should I rewrite this code?

Upvotes: 1

Views: 477

Answers (1)

Daniel C. Sobral
Daniel C. Sobral

Reputation: 297285

The problem with your code is that T is erased -- methods in bytecode do not have type parameters, so T is erased to Object and, therefore, true for everything.

This works, with some limitations:

import scala.reflect.ClassTag
object OptionCast {
  def apply[T : ClassTag](source : Any) : Option[T] = source match {
    case s : T => Some(s)
    case _ => None
  }
}

There are two important limitations here:

  1. It cannot check type parameters, because type parameters are erased are runtime. That means you can call OptionCast.apply[List[Int]](List("a")) and it will return Some(List("a")). To get around that, you have to get around type erasure.
  2. Any AnyVal class will be boxed, so you have to check against java.lang.Integer to catch Int, and so on.

Upvotes: 4

Related Questions