Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine whether a type parameter is a subtype of a trait?

Tags:

scala

Let's say I have the following types

class Foo
trait Bar

Is there a way to make a method which takes in a Type parameter, T, and determine if that T is a Bar? For example,

def isBar[T <: Foo: Manifest] = 
  classOf[Bar].isAssignableFrom(manifest[T].erasure)

Sadly, isBar[Foo with Bar] is false because erasure seems to erase mixins.

Also, manifest[Foo with Bar] <:< manifest[Bar] is false

Is this possible at all?

I looked at this question: How to tell if a Scala reified type extends a certain parent class?

but that answer doesn't work with mixed-in traits as they seem to be erased as evidenced above.

like image 221
TwistedNoodle Avatar asked Jun 20 '12 19:06

TwistedNoodle


1 Answers

This can be achieved with TypeTags (at least 2.10M7):

scala> class Foo; trait Bar
defined class Foo
defined trait Bar

scala> import reflect.runtime.universe._
import reflect.runtime.universe._

scala> def isBar[A <: Foo : TypeTag] = typeOf[A].baseClasses.contains(typeOf[Bar].typeSymbol)
isBar: [A <: Foo](implicit evidence$1: reflect.runtime.universe.TypeTag[A])Boolean

scala> isBar[Foo]
res43: Boolean = false

scala> isBar[Foo with Bar]
res44: Boolean = true

TypeTags provide a 1:1 translation of Scala types because they represent the types the compiler knows. Therefore they are much more powerful than plain old Manifests:

scala> val fooBar = typeTag[Foo with Bar]
fooBar: reflect.runtime.universe.TypeTag[Foo with Bar] = TypeTag[Foo with Bar]

With the method tpe we get full access to Scalas new Reflection:

scala> val tpe = fooBar.tpe // equivalent to typeOf[Foo with Bar]
tpe: reflect.runtime.universe.Type = Foo with Bar

scala> val tpe.<tab><tab> // lot of nice methods here
=:=                 asInstanceOf        asSeenFrom          baseClasses         baseType            contains            declaration         
declarations        erasure             exists              find                foreach             isInstanceOf        kind                
map                 member              members             narrow              normalize           substituteSymbols   substituteTypes     
takesTypeArgs       termSymbol          toString            typeConstructor     typeSymbol          widen  
like image 86
kiritsuku Avatar answered Oct 26 '22 15:10

kiritsuku