Skip to content

Instantly share code, notes, and snippets.

@fsarradin
Created July 1, 2013 08:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save fsarradin/5899220 to your computer and use it in GitHub Desktop.
Save fsarradin/5899220 to your computer and use it in GitHub Desktop.
PointAdder and scala type class
object Point {
trait PointAdder[P1, P2] {
def add(p1: P1, p2: P2): Point3D
}
case class Point2D(x: Int, y: Int)
case class Point3D(x: Int, y: Int, z: Int)
implicit object Point2DAdder extends PointAdder[Point2D, Point2D] {
def add(p1: Point2D, p2: Point2D): Point3D = Point3D(p1.x + p2.x, p1.y + p2.y, 0)
}
implicit object Point3DAdder extends PointAdder[Point3D, Point3D] {
def add(p1: Point3D, p2: Point3D): Point3D = Point3D(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z)
}
implicit object Point2DPoint3DAdder extends PointAdder[Point2D, Point3D] {
def add(p1: Point2D, p2: Point3D): Point3D = Point3D(p1.x + p2.x, p1.y + p2.y, p2.z)
}
implicit object Point3DPoint2DAdder extends PointAdder[Point3D, Point2D] {
def add(p1: Point3D, p2: Point2D): Point3D = Point3D(p1.x + p2.x, p1.y + p2.y, p1.z)
}
def main(args: Array[String]) {
val point1 = Point2D(1, 2)
val point2 = Point3D(1, 2, 3)
println(implicitly[PointAdder[Point2D, Point3D]].add(point1, point2))
}
}
@fsarradin
Copy link
Author

Comment faire pour avoir:

  • point1.add(point1)
  • point1.add(point2)
  • point2.add(point1)
  • point2.add(point2)

avec une conversion implicite générique ?

@evantill
Copy link

evantill commented Jul 1, 2013

point1.add(point1) retourne un Point2D ou un Poin3D ?

@fsarradin
Copy link
Author

D'après la solution de @huitseeker (https://gist.github.com/huitseeker/5901666)

object Point {

  trait PointAdder[P1, P2, P3] {
    def add(p2: P2): P3
    final def +(p2: P2): P3 = add(p2)
  }

  case class Point2D(x: Int, y: Int)
  case class Point3D(x: Int, y: Int, z: Int)

  implicit class Point2DAdder(p1: Point2D) extends PointAdder[Point2D, Point2D, Point2D] {
    def add(p2: Point2D): Point2D = Point2D(p1.x + p2.x, p1.y + p2.y)
  }

  implicit class Point3DAdder(p1: Point3D) extends PointAdder[Point3D, Point3D, Point3D] {
    def add(p2: Point3D): Point3D = Point3D(p1.x + p2.x, p1.y + p2.y, p1.z + p2.z)
  }

  implicit class Point2DPoint3DAdder(p1: Point2D) extends PointAdder[Point2D, Point3D, Point3D] {
    def add(p2: Point3D): Point3D = Point3D(p1.x + p2.x, p1.y + p2.y, p2.z)
  }

  implicit class Point3DPoint2DAdder(p1: Point3D) extends PointAdder[Point3D, Point2D, Point3D] {
    def add(p2: Point2D): Point3D = Point3D(p1.x + p2.x, p1.y + p2.y, p1.z)
  }

  def main(args: Array[String]) {
    val point1 = Point2D(1, 2)
    val point2 = Point3D(1, 2, 3)

    println(point1 + point1)
    println(point1 + point2)
    println(point2 + point1)
    println(point2 + point2)
  }

}

@dgalichet
Copy link

Sinon dans ta première version tu ajoutes simplement une méthode add :

def add[P1, P2](p1: P1, p2: P2)(implicit adder: PointAdder[P1, P2]): Point3D = adder.add(p1, p2)

c'est en gros le pattern CanBuildFrom utilisé dans les collections

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment