Note this is intended to be a community post, and examples should be added as needed. If you can't directly edit the answer to add examples (either problem examples or solutions), post in a comment with a link to a gist (or similar) or add a separate answer, to be integrated later.
There is the possibility that Scala 3 may not include scala.reflect.runtime at all (Dotty currently doesn't, and plans to do so are not certain). While answers that are applicable to both Scala 2 and Dotty might be preferred for transition purposes and for immediate improvements in performance, Dotty-specific solutions are also welcome.
https://www.cakesolutions.net/teamblogs/ways-to-pattern-match-generic-types-in-scala
TypeTags are generated at compile time (which may have significant compile time overhead due to macro expansion at each use-site) and employed at runtime, also generating some potential runtime overhead, depending on the exact nature of their use. So even in Scala 2, they should probably only be used a last resort (and we hope to address all such issues here, so that a last resort isn't necessary). By comparison, things that use instanceOf, directly or indirectly, are extremely fast.
instanceOf is super fast. classOf (i.e. Java's getClass) is nearly as fast.
Referential equality on ClassTags should also be very fast.
When possible, you may want to consider wrapping your type in a class, to give it a concrete "Java" type. While there will often be overhead, you can possibly use value classes.
Type classes on the wrapped class are then often a good way to expose functionality. As an aside, as @Blaisorblade pointed out, " type tags just a lawless type class (with methods typeName: String and tpe: Type) + instance materialization". Which brings us to the next option:
(currently not supported in Dotty, but planned)
Although perhaps a little harder to get used to, the end result should be cleaner syntax in the code employing the macro than if you were using a TypeTag. Also, macros have uses far beyond TypeTag.
A typical use case for TypeTag, taken from the popular post Scala: What is a TypeTag and how do I use it? is to perform ad-hoc polymorphism on a collection type:
import scala.reflect.runtime.universe._
def meth[A : TypeTag](xs: List[A]) = typeOf[A] match {
  case t if t =:= typeOf[String] => "list of strings"
  case t if t <:< typeOf[Foo] => "list of foos"
}
scala> meth(List("string"))
res67: String = list of strings
scala> meth(List(new Bar))
res68: String = list of foos
Unlike ClassTag, TypeTag is runtime reflection. Maybe I'm using it wrong here, though the behavior is quite surprising. At least in a REPL, I don't receive any warnings with the below:
def meth[A : ClassTag](xs: List[A]) = xs match {
  case xs: List[String] => "list of strings"
  case xs: List[Foo] => "list of foos"
}
meth(List(new Bar))   
res10: String = "list of strings" 
This is from @smarter on gitter (assumes we don't need to handle empty lists of different types separately):
def meth[A](xs: List[A]) = xs match {
   case Nil => "nil"
   case (_: String) :: _ => "list of strings"
   case (_: Foo) :: _ => 'list of foos"
}
This uses instanceOf, so it should be extremely fast.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With