On Nov 13, 9:26 am, AlexK <alexander.konstanti...@informatik.haw- hamburg.de> wrote: > Hi everybody, > > after playing around with protocols & datatypes, I found them very fun > to use. > Some questions: > Performance > I don't see (with my limited benchmarking) any significant difference > between multifns and protocolfns: > ... > This is what I have been expecting of course (Fn < Protocolfn < > Multifn), but i was thinking that with Protocols dispatching would be > significantly faster than with Multimethods. Am I missing something? > Because they don't seem to provide the speed for implementing the core > abstractions (like (seq <coll>)). >
This kind of do-nothing microbenchmarking demonstrates nothing. Protocol dispatching is significantly faster than multimethod dispatching, and I haven't even looked into call-site optimization. Protocol dispatch is not as fast as interface dispatch, and may or may not become so with call-site caching. But, protocols :on interfaces are precisely as fast when called with instances of the :on interface as calls to the :on interface. > Syntax > With protocols you define the protocols using symbols and extend types > by using the keywordized name > eg. > > (defprotocol Test (protocol-fn [it] "Protocol-fn")) > (extend Object Test {:protocol-fn (fn [it] nil)}) > > i understand that extend is a function and evaluates its arguments, > and that {:protocol-fn (fn [it] nil)} is a real map, but wouldn't it > be possible just to use a {<generic-fn> <new-method-fn>} map instead? > The protocol should know its generic functions, so that wouldn't be > ambiguous. > {protocol-fn (fn [it] nil)}) ; seems a lot clearer to me I wouldn't want to key anything off of fn identity. It would make mixins quite difficult. > > Extensibility > I've noticed that extending a protocol-fn redefines it: > > (def old-fn protocol-fn) ; from above > (extend Number Test {:protocol-fn (fn [it] :a-number)}) > (def new-fn protocol-fn) > > (= old-fn new-fn) > false > > this worries me, because the semantics are differing from MultiFns and > are less dynamic. They are no less dynamic, they just work differently. > Especially coupled with dynamic development this > could lead to some gotchas. > > Clojure 1.1.0-alpha-SNAPSHOT > user=> (defprotocol Test (prtcfn [it])) > Test > user=> (extend Object Test {:prtcfn (fn [it] :object)}) > nil > user=> (prtcfn (Object.)) > :object > user=> (def old-fn prtcfn) > #'user/old-fn > user=> (old-fn (Object.)) > :object > user=> (extend Number Test {:prtcfn (fn [it] :number)}) > nil > user=> (prtcfn (Object.)) > :object > user=> (prtcfn 1) > :number > user=> (def new-fn prtcfn) > #'user/new-fn > user=> (new-fn 1) > :number > user=> (old-fn 1) > :object > This is no different from ordinary functions: #'user/foo user=> (def old-foo foo) #'user/old-foo user=> (def foov #'foo) #'user/foov user=> (old-foo) :old-foo user=> (foov) :old-foo user=> (defn foo [] :new-foo) #'user/foo user=> (foo) :new-foo user=> (old-foo) :old-foo user=> (foov) :new-foo > When some protocol-fns get bound in a closure this could hurt a lot. > That claim is not supported by your example. In general, when making a long-term relationship with a function, you do so with its var, as above. A closure referencing a var closes over the var itself, not its current value: user=> (def f (future (dotimes [_ 10] (prn (foo)) (Thread/sleep 1000)))) #'user/f user=> :new-foo :new-foo :new-foo :new-foo :new-foo :new-foo :new-foo ;;;;;;;;;;;;;;;while that is going (defn foo [] :newer-foo) #'user/foo :newer-foo :newer-foo :newer-foo Admittedly, it is a difference from multimethods. With protocols, both protocols and their functions/methods are immutable. Redefining or extending a protocol modifies only the protocol and fn vars. I prefer that, and don't consider the above behavior a problem. What do others think? Rich -- 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