I'm trying to write a method in Scala that will take no arguments and will use a generic type to perform some logic in the method that will return output solely based on the generic type (similar to asInstanceOf[T]
or isInstanceOf[T]
).
It should be something like this:
val myObj = new MyClass
myObj.instanceOf[MyClass]
// returns true
This is what I thought may work.
class MyClass {
def instanceOf[Class[_]]: Bool = {
// ???
}
}
How do I implement this?
Thank you.
You could grab the type that was passed in by using ClassTags and use that.
A contrived example of what is asked in the title would be:
class Foo(name: String) {
def nameMatches[T: ClassTag]() =
classTag[T].runtimeClass.getName == name
}
new Foo("java.lang.String").nameMatches[String] //> res1: Boolean = true
new Foo("boolean").nameMatches[Boolean] //> res2: Boolean = true
This will work for the example you gave.
import scala.reflect.runtime.universe._
class MyClass {
def instanceOf[T: TypeTag] = typeOf[this.type] <:< typeOf[T]
}
Note that when you extend MyClass
you will need to override instanceOf
to get correct behaviour. Else you will get this:
scala> class MySubClass extends MyClass
defined class MySubClass
scala> (new MySubClass).instanceOf[MyClass] // works
res3: Boolean = true
scala> (new MySubClass).instanceOf[Any] // works
res4: Boolean = true
scala> (new MySubClass).instanceOf[MySubClass] // doesn't work
res5: Boolean = false
Another example of a generic method would be the standard library's implicitly
, which you can trivially implement yourself:
def implicitly[T](implicit ev: T) = ev
so you can do things like look up type class instances:
trait Show[T] { def shows(t: T): String }
case class Person(name: String, age: Int)
implicit val personShow = new Show[Person] { def show(p: Person) = s"${p.name} @ ${p.age} years" }
implicitly[Show[Person]]
this is useful in two cases:
you define a non-trivial type class instance using def
(i.e. you generically "generate" type class instances from instances of other type classes) and you're not sure you got it right:
implicit def terriblyNonTrivialTCInstance[T, U, V, W, Ñ](implicit ev1: Foo, ev2: Bar, ev3: Baz, ...): FooTC[T, U] = ...
implicitly[FooTC[MyType1, MyType2]] // compile error if the above definition is badly constructed
your method takes an implicit evidence but instead of using an implicit
arg list, you prefer to use a type bound, and later you'd like to grab an instance of the type class using implicitly
:
def myMethod[T: FooTC[T, Int]](t: T) = {
val ev = implicitly[FooTC[T, Int]]
ev.doSmth(t)
}
instead of:
def myMehtod[T](t: T)(implicit ev: FooTC[T, Int]) = {
ev.doSmth(t)
}
P.S. in the stdlib, implicitly
is implemented like this:
@inline def implicitly[T](implicit e: T) = e