Search code examples
scalaabstract-type

TypeTag for a type containing an abstract type


We have a trait Foo and are thinking about a method cast that takes a type parameter A <: Foo and a parameter f: Foo and returns Some(f: A) if f <: A, else None:

trait Foo
def cast[A <: Foo](f: Foo): Option[A] = ???

If Foo extendings will never be generic, then attaching a ClassTag is the conclusion:

def cast[A <: Foo : ClassTag](f: Foo) = f match {
  case f: A => Some(f)
  case _ => None
}
...
class Bar extends Foo
class Hoo extends Foo
println cast[Bar](new Bar) //→ Some(Bar)
println cast[Hoo](new Bar) //→ None

But what if there exists some Foo with an abstract type? Such like:

trait FooTyped extends Foo {
  type T
}

Then the cast just gets destroyed at all:

type FooT[A] = FooTyped{ type T = A }
...
val fint: FooT[Int] = new FooTyped{ type T = Int }
println cast[FooT[String]](fint) //→ Some(FooTyped) OH WHAT?

This happens because ClassTag doesn't care of type parameters and abstract types.

So we're going to use TypeTag that does keep track of them... But I don't know exactly how.

Please help me finish writing this article :(


Solution

  • ghik answer is correct. As a supplement I provide one possible way to achieve this:

    With this helper class:

    class Caster[B : TypeTag](f: B) {
      def cast[A <: Foo : TypeTag] = 
        if(typeOf[B] <:< typeOf[A]) Some(f) else None
    }
    

    You would get the expected answers like this:

    println(new Caster(new Bar).cast[Bar]) //→ Some(Bar)
    println(new Caster(new Bar).cast[Hoo]) //→ None
    println(new Caster(fint).cast[FooT[String]]) //→ None