I've been working on some scala code that was compiling fine, but somehow I've broken the implicit conversions and I can't work out what I've done wrong. Boiling it down to a very simple case, this code doesn't compile and the reason seems to be that I'm not importing the implicit conversions between Double and Numeric[Double]:
import scala.math.Numeric
import scala.math.Numeric._
import scala.math.Numeric.Implicits._
import Ordering.Implicits._
object ImplicitNumericConversions {
val v: Numeric[Double] = 3.0
}
I can fix this easily enough by providing my own function:
import scala.math.Numeric
object ImplicitNumericConversions {
def convertDoubleToNumeric(d: Double)(implicit num: Numeric[Double]): Numeric[Double] = num
val v: Numeric[Double] = convertDoubleToNumeric(3.0)
}
If I make the conversion function implicit then I get what I'm looking for:
import scala.math.Numeric
object ImplicitNumericConversions {
implicit def convertDoubleToNumeric(d: Double)(implicit num: Numeric[Double]): Numeric[Double] = num
val v: Numeric[Double] = 3.0
}
... but why don't the imports from scala.math.Numeric do this for me?
The actual problem that I'm working on looks like this:
class NumericRange[T <% Numeric[T]](val lower: T, val upper: T) { ... }
object NumericRange {
def apply[T](lower: T, upper: T)(implicit num: Numeric[T]) = {
import num._
new NumericRange[T](lower, upper)
}
}
... where the line creating the new NumericRange does not compile with these errors:
Multiple markers at this line
- No implicit view available from T => scala.math.Numeric[T].
- not enough arguments for constructor NumericRange: (implicit evidence$1: T => scala.math.Numeric[T])org.reductio.rtree.NumericRange[T]. Unspecified value parameter
evidence$1.
- not enough arguments for constructor NumericRange: (implicit evidence$1: T => scala.math.Numeric[T])org.reductio.rtree.NumericRange[T]. Unspecified value parameter
evidence$1.
- No implicit view available from T => scala.math.Numeric[T].
Numeric is a type class, which means you don't work with instances of Numeric[Double] in this way, but rather that you have a single implicit Numeric[Double] in scope that specifies how to perform numeric operations on Double (see my answer here for a related discussion of Ordering).
So you're looking for an implicit Numeric[T], not a T => Numeric[T]. And fortunately there is one of those in scope for Double, so you can just write:
class NumericRange[T: Numeric](val lower: T, val upper: T) { ... }
Or:
class NumericRange[T](val lower: T, val upper: T)(implicit
ev: Numeric[T]
) { ... }
The "context bound" in the first is just syntactic sugar for the implicit argument in the second.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With