Hi Meikel,

This is awesome! You just did a big chunk of what I was about to try
to do :). Sorry for the late response, I've been off the grid for a
few days...

With your second proposed solution, the defrecord-with-defaults macro,
 one can achieve very good performance while keeping some of the
features that implementation inheritance provides. I'll look into your
macro more closely and see if I can make it a seamless substitute for
defmacro.

Toni.

On Sat, Jul 17, 2010 at 4:02 AM, Meikel Brandmeyer <m...@kotka.de> wrote:
> Hi,
>
> one way to do that is using extend.
>
> (def defaults
>  {fn1 (fn ...)
>   fn2 (fn ...)
>   fn3 (fn ...)})
>
> (defrecord R1 [...])
> (def R1-fns
>  {fn1 (fn ...)})
>
> (defrecord R2 [...])
> (def R2-fns
>  {fn2 (fn ...)
>   fn3 (fn ...)})
>
> (extend YourProtocol
>  R1 (merge defaults R1-fns)
>  R2 (merge defaults R2-fns))
>
> Another way is the following macro:
>
> (defmacro defrecord-with-defaults
>  [record fields & protocol-default-fns]
>  (let [process-protocol
>        (fn [[protocol defaults fns]]
>          (let [defaults (when defaults
>                           (->> defaults
>                             resolve
>                             var-get
>                             (map (fn [[k f]]
>                                    (vector
>                                      k (cons (symbol (name k)) (next f)))))
>                             (into {})))]
>            (list* protocol
>                   (->> fns
>                     (map #(array-map (-> % first name keyword) %))
>                     (apply merge defaults)
>                     (map second)))))
>        split-protocols
>        (fn split-protocols
>          [p-d-fs]
>          (lazy-seq
>            (when-let [[p d & fs] (seq p-d-fs)]
>              (let [[fs next-p-d-fs] (split-with (complement symbol?) fs)]
>                (cons [p d fs] (split-protocols next-p-d-fs))))))]
>    `(defrecord ~record ~fields
>       ~@(mapcat process-protocol (split-protocols protocol-default-fns)))))
>
> Usage:
>
> (def foo-defaults
>  `{:bar (fn ([this# that#] nil))
>    :baz (fn [this# that#] nil)})
>
> (defrecord-with-defaults R [a b]
>  Foo foo-defaults
>  (bar [this that] nil)
>  Frob nil
>  (frobnicator [this] nil))
>
> Note: you have to syntax-quote the functions in the default map (as for 
> definline). And you can have only one arity per function. Here the 
> corresponding expansion:
>
> (clojure.core/defrecord FooImpl1 [a b]
>  Foo
>  (bar [this that] nil)
>  (baz [this__711__auto__ that__712__auto__] nil)
>  Frob
>  (frobnicator [this] nil))
>
> Sincerely
> Meikel
>
> --
> 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
> Note that posts from new members are moderated - please be patient with your 
> first post.
> 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



-- 
Antoni Batchelli
- twitter: @tbatchelli , @disclojure
--- email: tbatche...@gmail.com
----- web: tbatchelli.org , disclojure.org

-- 
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
Note that posts from new members are moderated - please be patient with your 
first post.
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