You're right. The following includes code for handling this case via setin and getin. I've also ditched macros, because that code couldn't support new lexical scopes in the setter/getter definition. setin getin support works by dynamically resolving getters and setters, thus this is slower than direct access via assoc-in and get-in.
Personally I have to say now that this is written, I prefer the terseness of: (set-x some-map v) over (assoc some-map :x v) This (get-x some-map) isn't as nice as (:x map) But it's also more explicit about how the map is being used- that a level indirection is required because the implementation might change. ;; ========================================== (comment (accessors x y z) ; {:x 4} (set-x {} 4) (defset x [m v] (assoc (assoc m :new "new") :x v)) ;; {:new "new", :x {:y {:z 1}}} (setin {:x {:y {:z 0}}} '(x y z) 1) ;; 0 (getin {:x {:y {:z 0}}} '(x y z)) ; {:x 4, :new "new", :foo 9} (let [z {:foo 9}] (set-x z 4)) ; 10 (let [y {:z 10}] (get-z y)) ; [0 1 2] (map get-x [{:x 0}, {:x 1}, {:x 2}])) (defn setter* [sym] `(defn ~(symbol (str "set-" sym)) [~'m ~'v] (assoc ~'m ~(keyword (str sym)) ~'v))) (defn getter* [sym] `(defn ~(symbol (str "get-" sym)) [~'m] (~(keyword (str sym)) ~'m))) (defmacro defset [sym args & forms] (let [set-sym (symbol (str "set-" sym))] `(defn ~set-sym [...@args] ~...@forms))) (defmacro defget [sym args & forms] (let [get-sym (symbol (str "get-" sym))] `(defn ~get-sym [...@args] ~...@forms))) (defn find-accessor [sym acc-type] (let [ns (or (namespace sym) (str *ns*)) sym-name (name sym)] (find-var (symbol ns (str (name acc-type) "-" sym-name))))) (defn setin [m [sym & syms] v] (let [setter (find-accessor sym :set) getter (find-accessor sym :get)] (if syms (setter m (set-in (getter m) syms v)) (setter m v)))) (defn getin [m [sym & syms]] (let [getter (find-accessor sym :get)] (if syms (getin (getter m) syms) (getter m)))) (defmacro accessors [& syms] `(do ~@(map setter* syms) ~@(map getter* syms))) On Sat, Apr 25, 2009 at 4:42 AM, MattH <mbhut...@gmail.com> wrote: > > It's worth considering how *nested* accessors would work in the > context of immutability. > > The nested maps approach works really nicely, due in part to functions > like assoc-in: > > ; From Mark Volkmann's tutorial > (assoc-in person [:employer :address :city] "Clayton") > > What would the above update look like if 'address' was accessed using > functions like get-address and set-address? > > Functions like assoc-in clearly rely on a uniform way of getting/ > setting fields (i.e. maps). > > My *hunch* is that the right avenue is to extend/implement clojure's > map classes if injecting behaviour is ever necessary. (A standard/ > supported way to do this would be nice.) > > I'd be happy using constructor functions like (make-complex-number) > and (make-person) which can hide detail of their implementations, but > I'd also like to benefit from all that goes with the idiomatic use of > maps. > > (My 2c) > > > --~--~---------~--~----~------------~-------~--~----~ You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en -~----------~----~----~----~------~----~------~--~---