Should implicit classes always extend AnyVal?

implicit-conversion, scala

Solution

Let's look at the limitations listed for value classes and think when they may not be suitable for implicit classes:

"must have only a primary constructor with exactly one public, val parameter whose type is not a value class." So if the class you are wrapping is itself a value class, you can't use an `implicit class` as a wrapper, but you can do this:

// wrapped class
class Meters(val value: Int) extends AnyVal { ... }

// wrapper
class RichMeters(val value: Int) extends AnyVal { ... }

object RichMeters { 
  implicit def wrap(m: Meter) = new RichMeter(m.value)
}

If your wrapper has implicit parameters as well, you can try to move them to the method declarations. I.e. instead of

implicit class RichFoo[T](foo: Foo[T])(implicit ord: Ordering[T]) {
  def bar(otherFoo: Foo[T]) = // something using ord
}

you have

implicit class RichFoo[T](foo: Foo[T]) extends AnyVal {
  def bar(otherFoo: Foo[T])(implicit ord: Ordering[T]) = // something using ord
}

"may not have specialized type parameters." You may want the wrapper to be specialized when wrapping a class which itself has specialized type parameters.

- "may not have nested or local classes, traits, or objects" Again, something which may well be useful for implementing a wrapper.

- "may not define a `equals` or `hashCode` method." Irrelevant, since implicit classes also shouldn't have `equals/hashCode`.

- "must be a top-level class or a member of a statically accessible object" This is also where you'd normally define implicit classes, but not required.

- "can only have defs as members. In particular, it cannot have lazy vals, vars, or vals as members." Implicit classes can have all of those, though I can't think of a sensible usecase for `var`s or `lazy val`s.

- "cannot be extended by another class." Again, implicit classes can be extended, but there is probably no good reason to.

In addition, making your implicit class a value class could possibly change some behavior of code using reflection, but reflection shouldn't normally see implicit classes.

If your implicit class does satisfy all of those limitations, I can't think of a reason not to make it a value class.

Problem

Say I'm writing an extension method ``` implicit class EnhancedFoo(foo: Foo) { def bar() { /* ... */ } } ``` Should you always include `extends AnyVal` in the class defininition? Under what circumstances would you not want to make an implicit class a value class?

Original source