Hacker News new | ask | show | jobs
by harperlee 2007 days ago
Through an atom (https://clojuredocs.org/clojure.core/atom). The idea of accesing a closure that is mutable is as follows:

  (let [temp (atom 0)]
    (defn getter [] @temp)
    (defn setter [val] (reset! temp val)))
To implement an object, you would do something more like:

  (defn new-object [init-val]
    (let [temp (atom init-val)]
       {:getter (fn [] @temp)
        :setter (fn [val] (reset! temp val))}))

  (def obj (new-object 0))
  ((:setter obj) 12)
To define interfaces, you could check whether the map/object conforms to a spec, etc.

But obviously all this is not very idiomatic; in clojure you would keep those functions first-class through defn instead of tying them to the object / map, and would pass state as an argument. Something like:

  (defn getter [obj] @obj)
  (defn setter [obj val] (reset! obj val))

  (def obj (atom 0)) ; This gives you the ability (and need) 
                     ; to explicitly track the list of 
                     ; existing objects in use lest they are garbage collected.

  (setter obj 12)
If obj has structure (e.g. it is a map such as {:type :my.personal/type :val 12}) you can identify its type through the type keyval and can check conformance to a spec, etc.

As it was said in the previous post, it's equivalent. It's a matter of how to organize code.

1 comments

That's a good explanation. Thanks!