Here is an overly simplistic example for illustration:
I can encapsulate an implementation detail such as using an atom for a counter:
(defn make-counter
([] (make-counter 0))
([init-val]
(let [c (atom init-val)]
{:get (fn [] @c)
:++ (fn [] (swap! c inc))})))
But that means I need to redefine everything to add a feature (no inheritance):
(defn make-bi-counter
([] (make-bi-counter 0))
([init-val]
(let [c (atom init-val)]
{:get (fn [] @c)
:++ (fn [] (swap! c inc))
:-- (fn [] (swap! c dec))})))
Whereas if it were possible to just extend the one function:
(assoc c :-- (env (:++ c) (fn [] (swap! c dec))))
(def c (make-counter))
(def b (make-bi-counter))
user=> ((:-- b))
-1
user=> ((:-- b))
-2
user=> ((:get b))
-2
Or I could have just exposed the atom and had independent functions:
(defn -- [a] (swap! a dec))
(def a (atom 0))
(-- a)
It appears the best option is to forgo encapsulation, if 'inheritance' (or perhaps more accurately: extension) is desirable.