; The Expression Problem and my sources: ; http://stackoverflow.com/questions/3596366/what-is-the-expression-problem ; http://blog.ontoillogical.com/blog/2014/10/18/solving-the-expression-problem-in-clojure/ ; http://eli.thegreenplace.net/2016/the-expression-problem-and-its-solutions/ ; http://www.ibm.com/developerworks/library/j-clojure-protocols/ ; To begin demonstrating the problem, we first need some ; "legacy code" with datastructures and functionality: ; data structures ("shapes") (defrecord Triangle [a b c]) (defrecord Square [edge]) ; protocols (defprotocol Areable (area [shape] "calculates the shape's area")) (defprotocol SelfAware (whoami [shape] "returns the name of the shape")) ; implementations (extend-type Triangle Areable (area [{:keys [a b c]}] "use Heron's formula to calculate area" (let [s (/ (+ a b c) 2)] (Math/sqrt (* s (- s a) (- s b) (- s c))))) SelfAware (whoami [this] "Triangle")) (extend-type Square Areable (area [this] (* (:edge this) (:edge this))) SelfAware (whoami [this] "Square")) ; Solving the Expression Problem ; 1. adding new functionality ; 2. adding new datastructures (that play well with existing functionality) ; 1. ; a new protocol is invented: Perimeterable ; can we add this new functionality without altering existing code ? ; => yes we can ! ; (defprotocol Perimeterable (perimeter [shape] "calculates the perimeter of the shape")) (extend-protocol Perimeterable Triangle (perimeter [{:keys [a b c]}] (+ a b c)) Square (perimeter [square] (* (:edge square) 4))) ; 2. ; a new shape is discovered: Circle ; can we add a this new shape without altering existing code ? ; => yes we can ! ; (defrecord Circle [r] Areable (area [this] (* Math/PI (Math/pow (:r this) 2))) SelfAware (whoami [this] "Circle") Perimeterable (perimeter [this] (* 2 (:r this)))) ; "tests" (area (->Triangle 1 1 1)) (whoami (->Triangle 1 1 1)) (perimeter (->Triangle 1 1 1)) (area (->Square 2)) (whoami (->Square 2)) (perimeter (->Square 2)) (area (->Circle 3)) (whoami (->Circle 3)) (perimeter (->Circle 3))