Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Too many implicits!

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

like image 819
Xiaohan Zhang Avatar asked Mar 11 '26 11:03

Xiaohan Zhang


1 Answers

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

like image 128
huynhjl Avatar answered Mar 14 '26 08:03

huynhjl