Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala Type Erasure on Option Match

Tags:

scala

object Test {
  def main(args: Array[String]) {
    val list: List[Double] = List(1.0, 2.0, 3.0, 4.0)
    val none = None

    case class Test()

    val test = Test()

    def f(x: Any) = x match {
        case _: Some[Test] => println("_ matched")
        case None => println("None matched")
    }

    f(list)
    f(none)
    f(test)
  }
}

Trying to compile the above code leads to an "eliminated by erasure" compile-time warning.

   $>scalac Test.scala
    Test.scala:11: warning: non-variable type argument Test in type pattern
 Some[Test] is unchecked since it is eliminated by erasure
            case _: Some[Test] => println("_ matched")
                    ^
    one warning found

I read this highly regarded Stackoverflow post, but I don't understand the type erasure here.

like image 528
Kevin Meredith Avatar asked Sep 04 '13 02:09

Kevin Meredith


People also ask

Does Scala have type erasure?

Type erasure refers to the runtime encoding of parameterized classes in Scala. It is simply performed by Scala compiler in which it removes all the generic type information after compilation. In Scala, generics are erased at runtime, which means that the runtime type of List[Int] and List[Boolean] is actually the same.

What is TypeTag in Scala?

TypeTags#TypeTag . A full type descriptor of a Scala type. For example, a TypeTag[List[String]] contains all type information, in this case, of type scala.

How does type erasure work?

Type erasure is a process in which compiler replaces a generic parameter with actual class or bridge method. In type erasure, compiler ensures that no extra classes are created and there is no runtime overhead.

What is manifest in Scala?

A Manifest[T] is an opaque descriptor for type T. Its supported use is to give access to the erasure of the type as a Class instance, as is necessary for the creation of native Arrays if the class is not known at compile time.


2 Answers

In runtime in jvm there is no Some[Test] or Some[String] there is only Some[Any]. So you can't match on Some[Test].

In this case you could match on content of Some like this:

case Some(e: Test) => println(s"$e matched")
like image 123
senia Avatar answered Oct 19 '22 20:10

senia


This is warning you that there is no way at runtime to determine if the value is Some[Test] and not, say, Some[Int], or Some[anything else]. This is due to the JVM not knowing about type parameters (i.e. the same reason that we have type erasure in Java). The post you reference shows a way provided in Scala to get around this type erasure issue, should you really need to ensure that you have a Some[Test] and not any other sub-type of Some. In your case, that does not appear to be relevant, so I wouldn't sweat the warning.

On the other hand, more idiomatic (and practical!) would be the following:

def f(x: Any) = x match {
    case Some(y) => println(s"x matched to Some - wrapped value is $y")
    case None => println("None matched")
}

This matches to Some[Any], but also provides the wrapped value for you to use directly inside the case block.

If you do need to be sure your value is of type Test, either try to wrap your head around TypeTags (the link you mentioned, or see here, for example) or you could resort to the somewhat nasty isInstanceOf method:

case Some(y) if (y.isInstanceOf[Test]) => ...

EDIT: or

case Some(e: Test) => ...

as per @senia's answer.

like image 21
Shadowlands Avatar answered Oct 19 '22 19:10

Shadowlands