Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

No ClassTag available for MyClass.this.T for an abstract type

This works well

class MyClass[T<: Actor: ClassTag] extends Actor {
  //....
}

but this doesn't due to the error No ClassTag available for MyClass.this.T

class MyClass extends Actor {
  type T<: Actor
  //...
}

even when do the following:

class MyClass extends Actor {
  type T<: Actor: ClassTag //this doesn't even compile
  //...
}

How do I use an abstract type and get rid of the error?

like image 649
Incerteza Avatar asked Dec 14 '13 06:12

Incerteza


1 Answers

class M[A <: B: C]

is short for

class M[A <: B](implicit c: C[A])

Therefore, if you move A to an abstract type member, you would have to write something like

abstract class M {
  type A <: B
  implicit protected def c: C[A]
}

and require anyone implementing M to provide such a value c. If you want M non-abstract, you must require a constructor value parameter of type C[A], which in turn means that type A must be constructor type parameter...


Edit to answer the comments: The notation A : C is defined as expanding to an implicit value parameter of type C[A]. There C is called context bound, and it can be understood as asking for a type class C[_] for type A. If you implement M you do not need to repeat the implicit modifier. Why is it there? Let me give you an example using a well-known type class Ordering:

 abstract class Foo {
   type A
   implicit protected def ord: Ordering[A]

   protected def seq: Seq[A]

   def range: (A, A) = {
     val xs = seq
     xs.min -> xs.max
   }
 }

If you removed implicit, you would have to change the calls to xs.min and xs.max which require an implicit Ordering.

object Bar extends Foo {
  type A = Int
  val seq = List(8, 34, 5, 21, 3, 13)
  val ord = Ordering.Int  // don't need to repeat `implicit`
}

Bar.range // (3, 34)

Here, Bar shows how you provide the implicit value parameter. This would be the same for ClassTag:

trait MyClass {
  type A
  implicit def tag: reflect.ClassTag[A]
}

object StringClass extends MyClass {
  type A = String
  // type String is statically known, thus compiler gives us this:
  val tag = reflect.classTag[String]
}

If your child class is generic again, you will need to pass on the responsibility for providing a class tag:

class GenericClass[A1](implicit val tag: reflect.ClassTag[A1]) {
  type A = A1
}
like image 103
0__ Avatar answered Sep 23 '22 05:09

0__