Reputation: 34884
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?
Upvotes: 9
Views: 3101
Reputation: 67280
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
}
Upvotes: 8