Skip to content

Instantly share code, notes, and snippets.

@kumarishan
Last active August 29, 2015 14:21
Show Gist options
  • Save kumarishan/f38fec3778fa92c55a07 to your computer and use it in GitHub Desktop.
Save kumarishan/f38fec3778fa92c55a07 to your computer and use it in GitHub Desktop.
Function matching over Type Parameter
import scala.reflect._
case class A(a: Int)
case class B[T](b: T)
object Example1 {
// [IMP] the names of vals has to be capital case
// so that they can be used in case statement.
// case statement requires stable identifiers and therefore
// in order to match, classOf[String] cannot be directly
// used.
val AClass = classOf[A]
val StringClass = classOf[String]
val BClass = classOf[B[Int]]
val ListClass = classOf[List[String]]
def foo(clazz: Class[_]) =
clazz match {
case AClass => "it's A"
case BClass => "it's B"
case StringClass => "it's String"
case ListClass => "it's list"
}
def fooBetter[T: ClassTag] =
implicitly[ClassTag[T]].runtimeClass match {
case AClass => "it's A"
case BClass => "it's B"
case StringClass => "it's String"
case ListClass => "it's list"
}
def bar[T: ClassTag](a: Int) =
implicitly[ClassTag[T]].runtimeClass match {
case AClass => s"it's A and $a"
case BClass => s"it's B and $a"
case StringClass => s"it's String and $a"
case ListClass => s"it's list and $a"
}
def notSoGoodBar(a: Int, clazz: Class[_]) =
clazz match {
case AClass => s"it's A and $a"
case BClass => s"it's B and $a"
case StringClass => s"it's String and $a"
case ListClass => s"it's list and $a"
}
def fromString(s: String): Class[_] =
s match {
case "a" => classOf[A]
case "b" => classOf[B[Any]]
case "string" => classOf[String]
case "list" => classOf[List[Any]]
}
def helo(args: Array[String]) {
println(foo(classOf[String])) // output -> it's String
println(foo(classOf[B[Int]])) // output -> it's B
println(foo(classOf[A])) // output -> it's A
println(foo(classOf[List[String]])) // output -> it's list
// If you passed classOf[B[String]] this will
// still give "it's B" even though we used
// BClass which is classOf[B[Int]].
// This happens because T of B[T] is erased by the compiler
// and classOf only represent the erased or runtime
// type i.e. B
println(foo(classOf[B[String]])) // output -> it's B
// you call also verify like this
println(classOf[B[String]] eq classOf[B[Int]]) // output -> true
// Now fooBetter makes the above code even more prettier
// by using ClassTag.
// This allows us to pass only the type in Type Parameter
// instead of passing Class[_] instance
println(fooBetter[String]) // output -> it's String
println(fooBetter[B[Int]]) // output -> it's B
println(fooBetter[A]) // output -> it's A
println(fooBetter[List[String]]) // output -> it's list
// This becomes even more useful when u have other parameters to
// pass too like in bar
println(bar[String](1)) // output -> it's String and 1
println(bar[B[Int]](1)) // output -> it's B and 1
println(bar[A](1)) // output -> it's A and 1
println(bar[List[String]](1)) // output -> it's list and 1
// certainly better than notSoGoodBar
// Therefore as long as only erased type infomation
// is needed to match and perform action. Then classOf
// or better yet ClassTag is the best way to do
// classOf vs ClassTag route
// Now what if you had a string and using that you
// want to retriev the type to be used and to call
// other classes that take action baed on type parameter
// First using classOf based methods
// This function takes a string, gets Class[_]
// object and passes it to foo
def aloha1(s: String) = {
val clazz = fromString(s)
foo(clazz)
}
// But if u wanted to user the fooBetter, i.e
// which uses the ClassTag on T type parameter
// same thing can be done like this
def aloha2(s: String) = {
implicit val tag = ClassTag(fromString(s)) // here tag's type is ClassTag[Nothing]
fooBetter // this will automatically take the above implicit val
}
// Well from first glance aloha1 appears to simple and faster.
// So lets check it.
val ps = Array("a", "b", "string", "list")
val itr = 1000000
val params = Array.fill(itr)(ps(Random.nextInt(4)))
var startTime = System.currentTimeMillis
for(i <- 0 until itr) aloha1(params(i))
println(s"Finished in ${System.currentTimeMillis - startTime}")
startTime = System.currentTimeMillis
for(i <- 0 until itr) aloha2(params(i))
println(s"Finished in ${System.currentTimeMillis - startTime}")
// The results of the above run proves that classOf way is more
// perfomant but its not really much big of a difference like 10 milliseconds
// in the above run
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment