Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you enrich value classes without overhead?

Scala 2.10 introduces value classes, which you specify by making your class extend AnyVal. There are many restrictions on value classes, but one of their huge advantages is that they allow extension methods without the penalty of creating a new class: unless boxing is required e.g. to put the value class in an array, it is simply the old class plus a set of methods that take the class as the first parameter. Thus,

implicit class Foo(val i: Int) extends AnyVal {
  def +*(j: Int) = i + j*j
}

unwraps to something that can be no more expensive than writing i + j*j yourself (once the JVM inlines the method call).

Unfortunately, one of the restrictions in SIP-15 which describes value classes is

  1. The underlying type of C may not be a value class.

If you have a value class that you can get your hands on, say, as a way to provide type-safe units without the overhead of boxing (unless you really need it):

class Meter(val meters: Double) extends AnyVal {
  def centimeters = meters*100.0                // No longer type-safe
  def +(m: Meter) = new Meter(meters+m.meters)  // Only works with Meter!
}

then is there a way to enrich Meter without object-creation overhead? The restriction in SIP-15 prevents the obvious

implicit class RichMeter(m: Meter) extends AnyVal { ... }

approach.

like image 201
Rex Kerr Avatar asked Feb 13 '13 19:02

Rex Kerr


People also ask

What is a value class?

What are Value Classes. At a fundamental level: value classes define objects which, once created, never change their value. A variable of a value type may only be changed by re-assigning to that variable.

What is value classes in Scala?

Value classes are a new mechanism which help to avoid allocating run time objects. AnyVal define value classes. Value classes are predefined, they coincide to the primitive kind of Java-like languages. There are nine predefined value types : Double, Float, Long, Int, Short, Byte, Char, Unit, and Boolean.

What is Scala AnyVal?

AnyVal is the root class of all value types, which describe values not implemented as objects in the underlying host system. Value classes are specified in Scala Language Specification, section 12.2. The standard implementation includes nine AnyVal subtypes: scala. Double, scala.

What is implicit class in Scala?

An implicit class is a class marked with the implicit keyword. This keyword makes the class's primary constructor available for implicit conversions when the class is in scope. Implicit classes were proposed in SIP-13.


1 Answers

In order to extend value classes, you need to recapture the underlying type. Since value classes are required to have their wrapped type accessible (val i not just i above), you can always do this. You can't use the handy implicit class shortcut, but you can still add the implicit conversion longhand. So, if you want to add a - method to Meter you must do something like

class RichMeter(val meters: Double) extends AnyVal {
  def -(m: Meter) = new Meter(meters - m.meters)
}
implicit def EnrichMeters(m: Meter) = new RichMeter(m.meters)

Note also that you are allowed to (freely) rewrap any parameters with the original value class, so if it has functionality that you rely on (e.g. it wraps a Long but performs complicated bit-mixing), you can just rewrap the underlying class in the value class you're trying to extend wherever you need it.

(Note also that you'll get a warning unless you import language.implicitConversions.)

Addendum: in Scala 2.11+, you may make the val private; for cases where this was done, you will not be able to use this trick.

like image 60
Rex Kerr Avatar answered Sep 23 '22 06:09

Rex Kerr