60

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?

Luigi Plinge
  • 50,650
  • 20
  • 113
  • 180

2 Answers2

58

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

  1. "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
    }
    
  2. "may not have specialized type parameters." You may want the wrapper to be specialized when wrapping a class which itself has specialized type parameters.

  3. "may not have nested or local classes, traits, or objects" Again, something which may well be useful for implementing a wrapper.
  4. "may not define a equals or hashCode method." Irrelevant, since implicit classes also shouldn't have equals/hashCode.
  5. "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.
  6. "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 vars or lazy vals.
  7. "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.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • fwiw, here's a use case for `lazy val` inside `implicit class`: https://gist.github.com/SethTisue/8977033 . Fortunately there's an easy workaround (also shown in the gist). – Seth Tisue Feb 13 '14 at 15:28
  • 2
    "I can't think of a reason not to make it a value class." -- because it's distracting but doesn't give any benefit. I haven't been able to reproduce the supposed memory benefits of "extends AnyVal" implicit classes in my tests. Do you have a cite for the benefits? – Rich Jun 29 '15 at 13:24
  • The documentation does still recommend it, but I can't measure any benefit in my tests. http://docs.scala-lang.org/overviews/core/value-classes.html – Rich Jun 29 '15 at 13:49
  • 1
    @Rich actually I agree - I did a microbenchmark and didn't find any benefit using `extends AnyVal`. Maybe the JVM eliminates the overhead of these short-lived objects by deciding not to create them. – Luigi Plinge Sep 10 '15 at 21:27
-5

I sense you're confusing Value Classes with Implicit Classes. You'd rarely extend anything when defining an Implicit Class for an enhancement while Value Classes must extend AnyVal.

Randall Schulz
  • 26,420
  • 4
  • 61
  • 81
  • 14
    I could rephrase the question as "should implicit classes always be value classes?". Why would you not want your implicit class to be a value class, if it eliminates the instance creation overhead? – Luigi Plinge Feb 18 '13 at 04:44
  • 3
    Value Classes have a lot of restrictions. If they're suitable, sure, use them for an enhancement. – Randall Schulz Feb 18 '13 at 04:48
  • 3
    > One use case for value classes is to combine them with implicit classes (SIP-13) for allocation-free extension methods. – Vojtech Letal Sep 04 '18 at 09:21