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