Max Power
Max Power

Reputation: 992

Scalac restrictions on value classes for implicits on traits with type parameters

The following does not compile because of extends AnyVal as it gives the following compilation error:

value class needs to have exactly one val parameter

Here's the code (simplified):

sealed trait Thing[A] {
  // stuff
}

object RichThing {
  implicit final class Implicits[A: ClassTag](val thing: A) extends AnyVal {

    def doSomething[B: ClassTag](f: A => B): Thing[A] = {
      // use f internally
    }
  }
}

The thing is that I cannot touch the library that Thing[A] is in and I'm trying to extend it so that for our internal users the additional functions feel seamless as per usual for implicit conversions.

I can remove AnyVal but is there a way around that restriction for my case (in 2.11)?

Upvotes: 1

Views: 260

Answers (1)

Kolmar
Kolmar

Reputation: 14224

A value class must have only one argument, and your Implicits class has two: the explicit val thing: A and an implicit one with type ClassTag[A] coming from the context bound [A: ClassTag].

To satisfy the value class requirement, you can move the implicit parameter ClassTag[A] from the context bound to individual functions signatures:

implicit final class Implicits[A](val thing: A) extends AnyVal {
  def doSomething[B: ClassTag](f: A => B)(implicit tagA: ClassTag[A]): Thing[A] = {
    // use f internally
  }
}

You are using this class just to provide rich methods, so it doesn't really matter at what point the implicits get injected.

Of course, you can just remove extends AnyVal, but then an actual Implcits object will be instantiated for every doSomething invocation, which is just needless pessimization.

Upvotes: 5

Related Questions