Top Banner
The Expression Problem Attila Magyar, 2016 Microsec ltd.
26

Expression problem

Mar 16, 2018

Download

Software

Attila Magyar
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: Expression problem

The Expression Problem

Attila Magyar, 2016Microsec ltd.

Page 2: Expression problem

Example● Types ● Operations

● Area● Perimeter● ..●

Area Perimeter ??

Square OK OK

Circle OK Ok

??

Page 3: Expression problem

Goals

● Adding a row (new type)● Adding a column (new operation)

Area Perimeter Draw

Square OK OK

Circle OK Ok

Triangle

Page 4: Expression problem

Constraints

● Extensibility● Code-level modularization

– no patching of existing code

● Separate compilation– independent deployability

● Static type safety (?)

Page 5: Expression problem

Basic class-based OO solution

interface Shape { double area(); double perimeter();}

class Square implements Shape { int a;

public Square(int a) { this.a = a; }

public double area() { return a*a; }

public double perimeter() { return 4*a; }}

Page 6: Expression problem

Basic class-based OO solution

class Circle implements Shape { int r;

public Circle(int r) { this.r = r; }

public double area() { return r*r*PI; }

public double perimeter() { return 2*r*PI; }}

class Triangle implements Shape { … }

Page 7: Expression problem

Basic class-based OO solution

● Adding a row (new type) → Easy

Area Perimeter Draw

Square OK OK ?

Circle OK Ok ?

Triangle OK OK ?

Page 8: Expression problem

Basic class-based OO solution

interface Shape { double area(); double perimeter();

void draw(); // New Operation

}

Page 9: Expression problem

Basic class-based OO solution

● Adding new row (new shape) → Easy● Adding a column (new operation) → Hard

Area Perimeter Draw

Square OK OK FAIL

Circle OK Ok FAIL

Triangle OK OK

Page 10: Expression problem

Basic procedural solution abstract class Shape { enum Type { SQUARE, CIRCLE } abstract Type type(); }

class Square extends Shape { public final int a; Square(int a) { this.a = a; }

Type type() { return SQUARE; } }

class Circle extends Shape { public final int r; Circle(int r) { this.r = r; }

Type type() { return CIRCLE; } }

static double area(Shape shape) { switch (shape.type()) { case SQUARE: return ((Square)shape).a * ((Square)shape).a; case CIRCLE: return ((Circle)shape).r * ((Circle)shape).r * PI; ... } }

Page 11: Expression problem

Basic procedural solution

static double perimeter(Shape shape) { switch (shape.type()) { case SQUARE: return 2 * ((Square)shape).a; case CIRCLE: return 2 * ((Circle)shape).r * PI; ... }}

static void draw(Shape shape) { switch (shape.type()) { case SQUARE: drawSquare(shape); case CIRCLE: drawCircle(shape); ... }}

Page 12: Expression problem

Basic procedural solution

● Adding a column (new operation) → Easy

Area Perimeter Draw

Square OK OK OK

Circle OK Ok Ok

Triangle ? ?

Page 13: Expression problem

Basic procedural solution

abstract class Shape { enum Type { SQUARE, CIRCLE, TRIANGLE } abstract Type type();}

static double perimeter(Shape shape) { switch (shape.type()) { case SQUARE: return 4 * ((Square)shape).a; case CIRCLE: return 2 * ((Circle)shape).r * PI; case TRIANGLE: … // New Shape ... }}

Page 14: Expression problem

Basic procedural solution

● Adding new row (new shape) → Hard● Adding a column (new operation) → Easy

Area Perimeter Draw

Square OK OK OK

Circle OK Ok Ok

Triangle FAIL FAIL

Page 15: Expression problem

OO with „visitor like” double dispatching

interface Visitor { void visitCircle(Circle circle); void visitSquare(Square square);}

class Square { public final int a; public Square(int a) { this.a = a; }

void accept(Visitor visitor) { visitor.visitSquare(this); }}

class Circle { public final int r; public Circle(int r) { this.r = r; }

void accept(Visitor visitor) { visitor.visitCircle(this); }}

class AreaCalculator implements Visitor { public double result;

public void visitCircle(Circle circle) { result = circle.r * circle.r * PI; } public void visitSquare(Square square) { result = 4 * square.a; }}

class PerimeterCalculator implements Visitor { ... }class Artist implements Visitor { ... }

Page 16: Expression problem

OO with „visitor like” double dispatching

● Adding a column (new operation/visitor) →Easy

● Adding new row (new shape) → Hard

Area Perimeter Draw

Square OK OK OK

Circle OK Ok Ok

Triangle FAIL FAIL

Page 17: Expression problem

Open classes

class Square { def a def area() { a * a } def perimeter() { 4 * a}}

class Circle { def r def area() { r * r * PI } def perimeter() { 2 * r * PI }}

Page 18: Expression problem

Open classes

Circle.metaClass.draw = { println "Drawing circle: $delegate"}

Square.metaClass.draw = { println "Drawing square: $delegate"}

def circle = new Circle(r: 12)circle.draw()

def square = new Square(a: 5)square.draw()

Page 19: Expression problem

Multi-methods

void m(SomeType object) {

// Single dispatch

object1.method(object2);}

Page 20: Expression problem

Multi-methods

void m(SomeType object) {

// Single dispatch

object1.method(object2);}

Receiver

Page 21: Expression problem

Multi-methods

interface Physical { void collideWith(Physical object); }

class Asteroid implements Physical { public void collideWith(Physical object) { // .. } }

class SpaceShip implements Physical { public void collideWith(Physical object) { // .. } }

spaceShip.collideWith(asteroid); // same action spaceShip.collideWith(spaceShip2); // same action

Page 22: Expression problem

Multimethods(defmulti collide (fn [this that] [(:type this) (:type that)]))

(defmethod collide [:SpaceShip :Asteroid ] [a b] "ship crashed by asteroid")(defmethod collide [:Asteroid :SpaceShip] [a b] "ship crashed by asteroid")(defmethod collide [:SpaceShip :SpaceShip] [a b] "ship ship encounter")(defmethod collide [:Asteroid :Asteroid ] [a b] "asteroid hit other asteroid")

(def ship1 {:type :SpaceShip :x 12 :y 46 :fuel 12 :rocket 45 :life 4})(def ship2 {:type :SpaceShip :x 24 :y 18 :fuel 62 :rocket 25 :life 7})(def asteroid {:type :Asteroid :x 4 :y 5})

(collide ship1 asteroid)(collide ship1 ship2)

Page 23: Expression problem

Multimethods

(def square1 {:type :Square :a 5})(def circle1 {:type :Circle :r 4})

(defmulti area (fn [this] [(:type this)]))(defmethod area [:Square] [this] (* (:a this) (:a this)))(defmethod area [:Circle] [this] (* 3.14 (* (:r this) (:r this))))

(defmulti perimeter (fn [this] [(:type this)]))(defmethod perimeter [:Square] [this] (* 4 (:a this)))(defmethod perimeter [:Circle] [this] (* 3.14 (* 2 (:r this))))

(area square1)(perimeter square1)

(area circle1)(perimeter circle1)

Page 24: Expression problem

Multimethods

; adding new Shape

(def triangle1 {:type :Triangle :a 2 :b 3 :c 4})

(defmethod area [:Triangle] [this] (triangle-area this))(defmethod perimeter [:Triangle] [this] (triangle-perimeter this))

; adding new operation

(defmulti draw (fn [this] [(:type this)]))

(defmethod draw [:Square] [this] (draw-square))(defmethod draw [:Circle] [this] (draw-circle))(defmethod draw [:Triangle] [this] (draw-triangle))

Page 25: Expression problem

Further solutions

● Clojure protocols● https://vimeo.com/11236603

● CLOS generic functionshttps://en.wikipedia.org/wiki/Common_Lisp_Object_System

● Type classes● https://en.wikipedia.org/wiki/Type_class

Page 26: Expression problem

References

● C9 Lectures: Dr. Ralf Lämmel - Advanced Functional Programming - The Expression Problem

● https://channel9.msdn.com/shows/Going+Deep/C9-Lectures-Dr-Ralf-Laemmel-Advanced-Functional-Programming-The-Expression-Problem/

● The Expression Problem, Philip Wadler, 12 November 1998

● http://homepages.inf.ed.ac.uk/wadler/papers/expression/expression.txt

● Clojure's Solutions to the Expression Problem

● https://www.infoq.com/presentations/Clojure-Expression-Problem

● Clojure 1.2 Protocols, Stuart Halloway

● https://vimeo.com/11236603