On Mon, Feb 28, 2011 at 8:32 AM, Chas Emerick <cemer...@snowtide.com> wrote: > I agree with your sentiment. This has been discussed before here: > > http://groups.google.com/group/clojure-dev/browse_frm/thread/fb3a0b03bf3ef8ca > > That discussion pretty quickly wandered into the weeds of whether this sort > of usage of protocols was intended or not, fundamentally programmer error or > not. There is as yet no input from clojure/core on either question. Maybe > someone would like to weigh in on the issue here?
I thought it was a goal of Java and JVM-hosted languages to avoid the dreaded "undefined behavior" bugbear of C, C++, and ilk. So I vote the behavior be made consistent -- say, the first applicable interface in the sequence applies, so in the example you posted earlier you'd get "sequential" consistently for vectors, and if you wanted "associative" instead you'd just swap the two pieces of the protocol so the case for Associative came first followed by the one for Sequential. Incidentally, a quick fix is as simple as changing a set to a sorted-set in clojure.core/supers: user=> (defprotocol Foo (foo [x])) (extend-protocol Foo clojure.lang.Sequential (foo [x] "sequential") clojure.lang.Associative (foo [x] "associative") ) (dotimes [_ 10] (println (foo []))) associative associative associative associative associative associative associative associative associative associative nil user=> (in-ns 'clojure.core) #<Namespace clojure.core> clojure.core=> (def old-supers supers) #'clojure.core/old-supers clojure.core=> (defn supers [x] (into (sorted-set-by #(.compareTo (.toString %2) (.toString %1))) (old-supers x))) #'clojure.core/supers clojure.core=> (in-ns 'user) #<Namespace user> user=> (supers (.getClass [])) #{java.util.concurrent.Callable java.util.RandomAccess java.util.List java.util.Collection java.lang.Runnable java.lang.Iterable java.lang.Comparable java.io.Serializable clojure.lang.Sequential clojure.lang.Seqable clojure.lang.Reversible clojure.lang.Indexed clojure.lang.IPersistentVector clojure.lang.IPersistentStack clojure.lang.IPersistentCollection clojure.lang.IObj clojure.lang.IMeta clojure.lang.ILookup clojure.lang.IFn clojure.lang.IEditableCollection ...} user=> (defprotocol Foo (foo [x])) (extend-protocol Foo clojure.lang.Sequential (foo [x] "sequential") clojure.lang.Associative (foo [x] "associative") ) (dotimes [_ 10] (println (foo []))) sequential sequential sequential sequential sequential sequential sequential sequential sequential sequential nil user=> I made it flip from associative to sequential in a single session by simply redefining supers to return a reverse-alphabetically-sorted set instead of an unsorted one. So if the clojure devs simply changed supers to return a sorted set with a comparator like that (I'd swap the %1 and the %2 to get ascending alphabetical order instead of descending) instead of an unsorted set the behavior would become consistent across runs; though it wouldn't generally use the first applicable protocol extension, it would use the same one every time. In fact it would use the alphabetically first by classname, so always Associative in this case whether you put Associative first or Sequential in defprotocol. Another enhancement to consider would be to implement a (prefer-protocol) or similar to override it. This would require not just going over the return from (seq (supers ...)) looking for the first match, as it apparently currently does, but doing some kind of (let [protos (reduce disj protocol-extensions (seq (supers ...)))] (choose-one-from-protos)) type setup. Both alternative enhancements make protocols a bit slower to invoke. The supers modification however needn't: just memoize supers and the cost of generating the set is incurred only once per session for each class of object that *any* protocol is invoked on. The further cost of making it a sorted set is likewise incurred only the once. -- 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