Last active
December 3, 2022 16:33
-
-
Save elnygren/e34368a86d62f0cb75f04ba903f7834a to your computer and use it in GitHub Desktop.
Solving the Expression Problem with Clojure
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; 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)) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment