In scala abstract class, if you want to define a context bound, you can simply use, e.g. [T: ClassTag] in parameter, however this is not possible in trait:
trait Foo[T: ClassTag]
Error:(11, 35) traits cannot have type parameters with context bounds `: ...' nor view bounds `<% ...'
trait Foo[T: ClassTag]
^
if you define:
trait Foo[T] {
implicit def ctg: ClassTag[T] = implicitly[ClassTag[T]]
}
object Bar extends Foo[Int]
then any attempt to read ctg inside Bar will trigger a StackOverflowError, as the implicit parameter becomes tail-recursive.
So what's the best way to allow ctg to be defined in a trait that automatically expose subclasses to context bound?
There isn't a nice way. A context bound is short-hand for an implicit parameter, and traits do not have parameters. That is, when you write:
class Foo[T : ClasTag]
The compiler de-sugars your code to:
class Foo[T](implicit ev: ClassTag[T])
This is of course not possible with a trait. If you must work around this with a trait, you can make the ClassTag
abstract, and force the class that extends it to implement it:
trait Foo[T] {
implicit def ctg: ClassTag[T]
}
object Bar extends Foo[Int] {
implicit val ctg = classTag[Int]
}
This looks slightly better with a class in the middle, so that you don't need to specify Int
twice when defining Bar
:
trait Foo[T] {
implicit def ctg: ClassTag[T]
}
class FooImpl[T](implicit val ctg: ClassTag[T]) extends Foo[T]
object Bar extends FooImpl[Int]