I'm writing a 2D Vector class whose declaration looks like:
case class Vec2(x:Float, y:Float) extends (Float, Float)(x, y) {
def +(v:Vec2) = Vec2(v.x+x, v.y+y)
//Subtract, dot product, projection, etc.
...
...
}
I'd like to be able to write things like Vec2(3, 7) + (2, 9) so I write
scala> implicit def ii2v2(i:(Int, Int)) = Vec2(i._1, i._2)
ii2v2: (i: (Int, Int))org.zhang.lib.misc.Vec2
scala> Vec2(2, 6) + (3, 1)
res25: org.zhang.lib.misc.Vec2 = (5.0,7.0)
Great. But the implicit won't work if I try Vec2(3, 7) + (2.6f, 9.3f), since (Float, Float) doesn't match (Int, Int). The only solution I've come up with is to write FOUR implicits, for (Int,Int), (Int, Float), (Float, Int), and (Float, Float).
The problem gets ridiculous when you try to account for doubles, or when you write a Vec3 class. Is there a way around this? I could just Vec2-ify everything but part of me just really wants to add an (Int, Int) to a Vec2 :)
Do this:
implicit def ii2v2[T: Numeric, U: Numeric](i:(T, U)) = {
import Numeric.Implicits._
Vec2(i._1.toFloat, i._2.toFloat)
}
This uses context bounds to tell the compiler to look for a Numeric[T] in scope which exist for the numeric types. The import Numeric.Implicits._ which is available since 2.9, allows to write toFloat.
On 2.8 you can write:
implicit def ii2v2[T, U](i:(T, U))(implicit num1: Numeric[T], num2: Numeric[U]) = {
Vec2(num1.toFloat(i._1), num2.toFloat(i._2))
}
See this other question which is similar: Writing a generic mean function in Scala
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