2

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 :)

Xiaohan Zhang
  • 113
  • 1
  • 3

2 Answers2

11

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

Community
  • 1
  • 1
huynhjl
  • 41,520
  • 14
  • 105
  • 158
2

You might wanna check out Numeric. Also see this question.

Community
  • 1
  • 1
agilesteel
  • 16,775
  • 6
  • 44
  • 55