--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@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+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
I get the idea, but I don't see how this would help provide a default
implementation for the functions inside a protocol. It looks to me
like this would be the same as creating a record with only some of the
functions implemented. Or am I reading it wrong?
Thanks for your input.
Toni.
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@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+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
--
Antoni Batchelli
- twitter: @tbatchelli , @disclojure
--- email: tbatc...@gmail.com
----- web: tbatchelli.org , disclojure.org
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
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.
Could you try by calling m and not .m1?
Apologies.
Am 21.08.2010 um 07:33 schrieb Toni Batchelli:
> (dotimes [_ 10] (time (dotimes [_ 10000] (.m1 my-simple-P "hello")))) ;
>
> "Elapsed time: 131.973 msecs"
I think you get caught by reflection here. As Nicholas said, you should call m1, not .m1.
Sincerely
Meikel