2

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?

tribbloid
  • 4,026
  • 14
  • 64
  • 103

1 Answers1

8

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]
Michael Zajac
  • 55,144
  • 7
  • 113
  • 138
  • 1
    Thank you. Sad to know that it's not supported, hope an automatic de-sugaring can become a feature in the future – tribbloid May 17 '16 at 03:28