How to encapsulate in clojure?
clojure, encapsulation, wrapper
Solution
You can use protocols.
First a Clojure record:
(defprotocol Rectangular
(left [this])
(right [this]))
(defrecord Rect [x y w h]
Rectangular
(left [this] x)
(right [this] (+ x w)))
(def my-rect (Rect. 1 2 3 4))
(right my-rect) ;=> 4
Now a Java object:
(import java.awt.Rectangle)
(extend-type Rectangle
Rectangular
(left [this] (int (.getX this)))
(right [this] (int (+ (.getX this) (.getWidth this)))))
(def my-other-rect (Rectangle. 1 2 3 4))
(right my-other-rect) ;=> 4
Problem
I have some clojure code that looks like this: ``` (defn rect [x y w h] {:x x, :y y, :w w, :h h}) (def left :x) (def top :y) (def width :w) (def height :h) (defn right [r] (+ (left r) (width r))) (defn bottom [r] (+ (top r) (height r))) ``` Now the following code seems a bit uncommon: ``` (def left :x) ``` However I don't know any other way to get encapsulation. Suppose, I later want to represent my rect a different way. Then relying on (:x rect) is not a good idea, because :x only works on hashmap's and records, so then I would be leaking implementation details in the api, which at least in OO languages is considered bad practice. Now, if I decide to implement my rect in java instead, it gets even worse, because then I would have to write wrappers like: ``` (defn left [rect] (.getLeft rect)) ``` to make sure the interface doesn't change. How does clojure get around this problem?