Scala pattern matching on generic type with TypeTag generates a warning while ClassTag not?

霸气de小男生 提交于 2019-12-04 09:57:08

You don't see a warning for classTag because that check simply works for those:

scala> matchClass[Int]("aaa")
res82: String = not A

scala> matchClass[Int](5)
res83: String = it's A 

And doesn't work for typeTag:

scala> matchType[Int](5)
res84: String = it's A

scala> matchType[Int]("aaa")
res85: String = it's A

The reason is that for pattern matching on classTags (when it's seeing an implicit) compiler generates something like:

case a: A if classTag[A].runtimeClass.isInstance(a) => ...

There is no way to get runtimeClass for TypeTags in general (considering both compile&runtime, see the UPDATE for a specific case allowing to extract it in runtime only), so that's why compiler doesn’t transform them. By default, pattern matching can't match on generic (polymorphic) types because of erasure, so you can see that warning by default:

 scala> def matchGeneric[A](v: Any) =
 |     v match {
 |         case a: A => "it's A"
 |         case _ => "not A"
 |     }
<console>:28: warning: abstract type pattern A is unchecked since it is eliminated by erasure
               case a: A => "it's A"
                       ^
matchGeneric: [A](v: Any)String

UPDATE: As @Seth Tisue mentioned when a tag comes from run-time universe (only) you can get a runtime class for it (but you gonna have to create a mirror first).


Reference:

As per scaladocs of ClassTag itself:

The compiler tries to turn unchecked type tests in pattern matches into checked ones by wrapping a (_: T) type pattern as ct(_: T), where ct is the ClassTag[T] instance. Type tests necessary before calling other extractors are treated similarly. SomeExtractor(...) is turned into ct(SomeExtractor(...)) if T in SomeExtractor.unapply(x: T) is uncheckable, but we have an instance of ClassTag[T].

TypeTag scaladocs and language spec itself don't mention any such functionality for TypeTags


Speculative explanation

There is no way to know for certain why some features are implemented or not, so any speculation would be opinionated (and out of SO scope, and isn't even related to your question directly, but to answer @Tom's comment). Nevertheless (as of 2.12)...

This is probably because "ClassTags provide access only to the runtime class of a type" and are part of scala-library (even though their package is scala.reflect.), while TypeTags are a part of a separate (and quite wide-broad) reflection API thus are meant to refer to either compile or run time depending on the universe they're in, so writing the additional checks (during synthesis!!) for those would be not just confusing (for users) but also hard for language developers: synthesis itself is in a different (compiler) module and [synthesis] doesn't depend on reflection (only scala-library) as pattern matching synthesis is happening on early "patmat" stage. Also, scala spec (12.3.4.2 Variance) mentions usage of ClassTag's for synthetic adjustments of array instantiations which (very speculatively) could mean that ClassTags are more integrated with the "syntax sugar"-features.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!