Skip to content

Instantly share code, notes, and snippets.

@almendar
Last active October 15, 2018 13:47
Show Gist options
  • Save almendar/182fda56f88d4098c6f48a34e323f330 to your computer and use it in GitHub Desktop.
Save almendar/182fda56f88d4098c6f48a34e323f330 to your computer and use it in GitHub Desktop.
Functional dynamic dispatch
case class Circle(radius: Double)
case class Rectangle(x: Double, y: Double)
case class Square(x: Double)
trait ShapeOps[T] {
def perimter(t: T): Double
def area(t: T): Double
}
object ShapeOps {
val circleShapeOps: ShapeOps[Circle] = new ShapeOps[Circle] {
override def perimter(t: Circle): Double = 2 * Math.PI * t.radius
override def area(t: Circle): Double = Math.PI * t.radius * t.radius
}
val recangleShapeOps: ShapeOps[Rectangle] = new ShapeOps[Rectangle] {
override def perimter(t: Rectangle): Double = 2 * (t.x + t.y)
override def area(t: Rectangle): Double = t.x * t.y
}
}
trait Shape {
type T
def ops: ShapeOps[T]
def t: T
override def toString: String = t.toString
}
object Shape extends ShapeOps[Shape] {
//Smart constructors
def circle(radius: Double): Shape = new Shape {
override type T = Circle
override def ops: ShapeOps[Circle] = ShapeOps.circleShapeOps
override def t: T = Circle(radius)
}
def rectangle(x: Double, y: Double): Shape = new Shape {
override type T = Rectangle
override def ops: ShapeOps[Rectangle] = ShapeOps.recangleShapeOps
override def t: Rectangle = Rectangle(x, y)
}
override def perimter(t: Shape): Double = t.ops.perimter(t.t)
override def area(t: Shape): Double = t.ops.area(t.t)
}
val shapes: Seq[Shape] = List(
Shape.circle(22),
Shape.rectangle(34, 56)
)
val totalArea = shapes.map(Shape.area).sum
println(s"Total area $totalArea")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment