David Nolen <dnolen.li...@gmail.com> writes: Hi David,
>> I think it might be a good idea to discuss why the Java interfaces >> are created for protocols. > > I don't see how polyfns can be as fast as protocol functions that are > defined inline and thus backed by an Java interface. It has not been > my experience that this is true at all. extending to a type later is > expressive but takes a measurable performance hit as far as I've seen. Just tested that. --8<---------------cut here---------------start------------->8--- user> (defprotocol PFoo (foo [this])) PFoo user> (extend-protocol PFoo String (foo [this] :string) Number (foo [this] :number)) nil user> (let [x 1, y "foo"] (time (dotimes [_ 1000000] (foo x) (foo y)))) "Elapsed time: 69.700106 msecs" nil user> (deftype X [] PFoo (foo [this] :x)) user.X user> (deftype Y [] PFoo (foo [this] :y)) user.Y user> (let [x (->X), y (->Y)] (time (dotimes [_ 1000000] (foo x) (foo y)))) "Elapsed time: 7.794859 msecs" nil --8<---------------cut here---------------end--------------->8--- So indeed type dispatch with inline implementations seems to be nearly an order of magnitude faster than the cache-lookup based dispatch you have when extending protocols using extend. And multimethods are even much slower: --8<---------------cut here---------------start------------->8--- user> (defmulti multifoo class) nil user> (defmethod multifoo String [s] :string) #<MultiFn clojure.lang.MultiFn@3ae95911> user> (defmethod multifoo Number [n] :number) #<MultiFn clojure.lang.MultiFn@3ae95911> user> (let [x 1, y "x"] (time (dotimes [_ 1000000] (multifoo x) (multifoo y)))) "Elapsed time: 348.201964 msecs" nil user> (let [x 1, y "x"] (time (dotimes [_ 1000000] (multifoo x) (multifoo y)))) "Elapsed time: 338.420101 msecs" nil --8<---------------cut here---------------end--------------->8--- Well, but I still see a use-case for polyfns namely in the situation where you'd usually use a protocol and extend it to existing (java) types you have no control over, and you don't need the generated interface. That applies to many of my protocols. But on the other hand, many of my protocols aren't open but merely an implementation detail, and they are extended upon only a few java classes (many only 2). For those it seems to be more efficient to use a plain function explicitly dispatching on type using `instance?'... --8<---------------cut here---------------start------------->8--- user> (defn foofn [x] (cond (instance? String x) :string (instance? Number x) :number :else (throw (RuntimeException. "BANG")))) #'user/foofn user> (time (let [o1 1, o2 "x"] (dotimes [_ 1000000] (foofn o1) (foofn o2)))) "Elapsed time: 13.263767 msecs" nil --8<---------------cut here---------------end--------------->8--- Bye, Tassilo -- 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