// Subtype experiments class Point(val x: Double, val y: Double) { def getX() : Double = x def getY() : Double = y def distFromOrigin() : Double = { Math.sqrt(getX()*getX() + getY()*getY()) } } class ColorPoint(x: Double, y: Double, val color: String) extends Point(x,y) { def getColor() : String = { color } } class A { def shift(p: Point) : Point = { new Point(p.getX() - 10, p.getY() + 10) } } class B extends A { def shift(cp: ColorPoint) : ColorPoint = { if (cp.getColor().equals("red")) { new ColorPoint(cp.getX(), cp.getY() + 10, "blue") } else { cp } } } class C { def shift(cp: ColorPoint) : Point = { if (cp.getColor().equals("red")) { new Point(cp.getX(), cp.getY() + 10) } else { cp } } } class D { def shift(p: Point) : ColorPoint = { new ColorPoint(p.getX() - 10, p.getY(), "blue") } } val p = new Point(1,2) val cp = new ColorPoint(3,4,"red") /* Consider possible combinations of: ShifterType: choose from A, B, C, D ShifterActual: choose from A, B, C, D Arg: choose from Point, ColorPoint Result: choose from Point, ColorPoint */ val shifter: ShifterType = new ShifterActual() val result: Result = shifter.shift(new Arg(...)) /* Example: */ // assume: CP -> CP, actual: P -> P val shifterA: B = new A() // Can anything go wrong inside shift? // Can anything go wrong calling methods on result1 or result2? val result2: ColorPoint = shifterA.shift(new ColorPoint(...)) val c = result2.getColor()