asInstanceOfOption[A]

Is there a good way to get an Option back if asInstanceOf turns out not to work? I’d like something similar to head & headOption, max & maxOption so that

"wrong".asInstanceOfOption[Int].getOrElse(-1)
5.asInstanceOfOption[String].getOrElse("wrong")

work. In the code below, result1 is wrong even though result2 is right, so that I can’t generalize this into a function.

  import scala.util.Try

  def asInstanceOfOption[A](any: Any): Option[A] = Try { any.asInstanceOf[A] }.toOption

  val example: Any = List(42)
  val result1 = asInstanceOfOption[String](example)
  val result2 = Try { example.asInstanceOf[String] }.toOption

I think what you’re running into is type erasure. Scala has ClassTag that lets you do things that require you know a generic type at runtime.

def asInstanceOfOption[A](any: Any)(implicit tag: ClassTag[A]): Option[A] = {
  tag.unapply(any)
}

Wonderful and elegant. That unapply is perfect!

Shapeless offers a cast, random link.

I think you meant:

def asInstanceOfOption[A](any: A)(implicit tag: ClassTag[A]): Option[A] = {
  tag.unapply(any)
}

At least in Scala 3, your version did not compile with:

    val op1 = asInstanceOfOption0("wrong").getOrElse(-1)
    val op2 = asInstanceOfOption0(5).getOrElse("wrong")    

If i understand you correctly you want to let the method asInstanceOfOption work directly on the instance itself. To that end you can use something like (Scala 3):

import scala.reflect.ClassTag

object cast :
  extension [T](_value: T) 
    def asInstanceOfOption[M: ClassTag]: Option[M] = _value match
      case any: M => Some(any)
      case _      => None 

import cast._

val r1 = "wrong".asInstanceOfOption[Int].getOrElse(-1)
val r2 = 5.asInstanceOfOption[String].getOrElse("wrong")

see Scastie for the running example.

1 Like