GENIOUS idea Laurent ;)
Extremely terse and uniform. Also because I switched the implementation to
use multimethods, performance has jumped quite a bit. In fact if you memoize
find-accessors, the code is only a little bit slower than
update-in/assoc-in/get-in! The defset and defget macros now check to make
sure their definition only defines 2 or 1 arguments respectively.
find-accessor throws an error if you attempt to use an accessor in acc-in
that hasn't been previously defined .

The code is for now hosted here
http://github.com/swannodette/accessors/tree/master.

Does anybody care to see this in contrib? If so I'll send in my CLA :)

(comment
  (accessors x y z)

  ; {:x 4}
  (acc-x {} 4)

  ; 4
  (acc-x {:x 4})

  (defset x [m v]
    (assoc (assoc m :new "new") :x v))

  ;; {:new "new", :x {:y {:z 1}}}
  (acc-in {:x {:y {:z 0}}} '(x y z) 1)

  ;; 0
  (acc-in {:x {:y {:z 0}}} '(x y z))

  ; {:x 4, :new "new", :foo 9}
  (let [z {:foo 9}]
    (acc-x z 4))

  ; 10
  (let [y {:z 10}]
    (acc-z y))

  ; [0 1 2]
  (map acc-x [{:x 0}, {:x 1}, {:x 2}])

  ; performance ----------

  ; ~180ms 2.53ghz MBP Core2Duo
  (time (dotimes [x 100000]
  (assoc-in {:x {:y {:z 0}}} [:x :y :z] 1)))

  ; ~700ms 2.53ghz MBP Core2Duo
  (time (dotimes [x 100000]
  (acc-in {:x {:y {:z 0}}} '(x y z) 1)))

  ; ~300ms 2.53ghz MBP Core2Duo
  (def find-accessor (memoize find-accessor))
  (time (dotimes [x 100000]
  (acc-in {:x {:y {:z 0}}} '(x y z) 1)))
)

On Sun, Apr 26, 2009 at 6:27 PM, Laurent PETIT <laurent.pe...@gmail.com>wrote:

>
> Hello,
>
> Maybe you should consider creating a single function with 2 arities:
> with one argument, it's the getter, with two arguments, it's the
> setter (that returns the new type) !
>
>
> (prop-foo obj) ; --> returns the property prop-foo
> (prop-foo obj newval) ; --> returns a new version of obj with prop-foo
> property set to newval
>
> Terse and uniform :-)
>
> ?
>
>
>
> 2009/4/26 David Nolen <dnolen.li...@gmail.com>:
> > 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
-~----------~----~----~----~------~----~------~--~---

Reply via email to