I would like to have a run time check on a Double, without having to scatter the check all over my code.
I thought that defining an implicit class
would do the job, something on the line:
implicit class Probability(val x: Double) {
require(x >= 0.0 && x <= 1.0, "Probs are defined btw 0.0 and 1.0")
}
The missing part, is then to tell Scala to treat Probability as a Double
any time after it's construction. For this I suppose it is necessary to require a double side conversion.
object Foo {
implicit class Probability(val x: Double) {
require(x >= 0.0 && x <= 1.0, "Probs are defined btw 0.0 and 1.0")
}
implicit def asDouble(e: Probability): Double = e.x
implicit def asProb(d: Double): Probability = new Probability(d)
def max_(s: Seq[Double]): Double = {
s.max
}
def max(s: Seq[Probability]): Double = {
s.max
}
}
val r1 = Foo.max_(List(2.0, 3.0, 5.0))
val r2 = Foo.max(List[Probability]=(2.0, 3.0, 5.0))
EDIT
This might have done the trick. Not sure what happens under the hood.
trait RangeBound
type Probability = Double with RangeBound
implicit def makeProb(p: Double): Probability = {
assert (p >= 0.0 && p <= 1.0)
p.asInstanceOf[Probability]
}
val p = List[Probability](0.1, 0.3, 0.2)
val r = p filter (_ > 0.1)
Because this does not work:
trait RangeBound
type Probability = Double with RangeBound
implicit def makeProb(p: Double): Probability = {
assert (p >= 0.0 && p <= 1.0)
p.asInstanceOf[Probability]
}
val p = List[Probability](0.1, 0.3, 0.2)
val r2 = p.max
with the error:
Error:(10, 18) No implicit Ordering defined for Double with A$A288.this.RangeBound.
lazy val r2 = p.max;}
^
This enabled basic run time checks: