I think I've answered at least part of my own question.  This is the
simplest ambiguous case I've found:

a        b
|         |
----------
    |
    c

user> (defmulti test-prefer :tag)
#'user/test-prefer
user> (defmethod test-prefer ::a [h] "a")
#<MultiFn clojure.lang.mult...@6551c1>
user> (defmethod test-prefer ::b [h] "b")
#<MultiFn clojure.lang.mult...@6551c1>
user> (derive ::c ::a)
nil
user> (derive ::c ::b)
nil
user> (test-prefer {:tag ::a})
"a"
user> (test-prefer {:tag ::b})
"b"
user> (test-prefer {:tag ::c})
; Evaluation aborted.
user> (prefer-method test-prefer ::a ::b)
#<MultiFn clojure.lang.mult...@6551c1>
user> (test-prefer {:tag ::c})
"a"

So if I understand correctly, the crux of the problem is that this
preference information is not part of the actual derive hierarchy.
This gives added flexibility to customize on a method by method basis,
but at a cost.
One cost seems to be that if an outside user wants to write a new
method on this very same type hierarchy, he can only do it if he knows
how the types are derived from one another inside the library so that
he can restate all the necessary precedences with appropriate
prefer-method calls on his own new method.

Another interesting question is whether at least test-prefer is safe
for extension.  Here's a potential problem I see.  Let's say that in
the above example, type ::c is what is intended to be publicly
visible, and the base classes ::a or ::b just provide the base
implementation for various methods, including prefer-method.

I may come along and want to extend test-prefer to a type ::d which
derives from ::c and ::e, where ::e provides an alternative
implementation.

a        b                   (a and b are intended to be hidden from end-user)
|         |
----------
    |
    c          e
    |           |
    ------------
         |
         d


(derive ::d ::c)
(derive ::d ::e)
(defmethod test-prefer ::e [h] "e")

Now, as an external user, I know nothing about where test-prefer on
::c gets its behavior.  Obviously, I have to disambiguate between
whether test-prefer chooses ::c over ::e, so I may try something like
this:
(prefer-method test-prefer ::c ::e)

But this will not work.  I still get an error saying I need to
disambiguate between ::a and ::e.  And not knowing anything about ::a,
I could be very confused, and not know how to provide this
information.

Considering how complex the situation can get with single dispatch, I
imagine it gets even more complex in multiple dispatch situations.  In
the multimethods example at clojure.org/multimethods, an example is
given of disambiguating between [::shape ::rect] and [::rect ::shape].
 But again, if you're writing the bar method from outside of the
library which defines ::shape and ::rect, you might not even know
which is more specific.  It might be easier to choose a strategy, such
as more specific on the leftmost taking precedence, than to know the
details of how the various types in the library interact.

Anyway, this is my attempt to digest and restate what I've learned
from this thread and from tinkering around.  Any other good examples
that illustrate some of the difficulties?

--~--~---------~--~----~------------~-------~--~----~
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
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