I think I understand the new "value class" feature of Scala 2.10, by comparison with Haskell's newtype
:
trait BoundedValue[+This] extends Any { this: This =>
def upperBound: This
def lowerBound: This
}
class Probability @throws(classOf[IllegalArgumentException]) (v: Double) extends AnyVal with BoundedValue[Probability] {
val value: Double = if ((v >= 0.0) && (v <= 1.0)) v else throw new IllegalArgumentException((v.toString) + "is not within the range [0.0, 1.0]")
override val upperBound: Probability = new Probability(0.0)
override val lowerBound: Probability = new Probability(1.0)
// Implement probability arithmetic here;
// will be represented by Double at runtime.
}
The question I have is, how does a value class appear to Java code that uses the Scala package in which it is declared? Does the value class appear as a reference class from the Java side, or is it erased completely (and thus appears as the type it wraps)? In other words, how type-safe are value classes when Java is involved on the source level?
EDIT
The code above won't compile, according to the SIP-15 document (linked in Daniel's answer), because value classes aren't allowed to have any initialization logic, because either v
must be explicitly a val or Probability
must have an unbox
method and a corresponding box
method on it's companion object, and because value classes must have exactly one field. The correct code is:
trait BoundedValue[This <: BoundedValue[This]] extends Any { this: This =>
def upperBound: This
def lowerBound: This
}
class Probability private[Probability] (value: Double) extends AnyVal with BoundedValue[Probability] {
@inline override def upperBound: Probability = new Probability(0.0)
@inline override def lowerBound: Probability = new Probability(1.0)
@inline def unbox: Double = value
// Implement probability arithmetic here;
// will be represented by Double at runtime (mostly).
}
object Probability {
@throws(classOf[IllegalArgumentException])
def box(v: Double): Probability = if ((v >= 0.0) && (v <= 1.0)) new Probability(v) else throw new IllegalArgumentException((v.toString) + "is not within the range [0.0, 1.0]")
}
The question itself is still valid as is, however.