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

Reply via email to