Welcome! Please see the About page for a little more info on how this works.

0 votes
in ClojureScript by
edited by
  1. Wondering about these two loops in cljs.core/prefers*. Am I misreading it, or do they always return nil? Seems like the result of the inner when, which makes the recursive call to prefers*, is always dropped.

  2. Also, if the intent of these two loops is a polymorphic lookup against the prefers table, should the calls to parents also be against the same hierarchy as with the isa? in cljs.core/dominates? Currently they are made against the global hierarchy.

  3. Also, if there is no prefers table, or it is empty, you can probably skip the loops.

1 Answer

0 votes

I suspect that code probably derives from the Clojure code in MultiFn, which had that bug with the hierarchy (and was fixed in 1.11 - see https://clojure.atlassian.net/browse/CLJ-2234 ).

Thanks Alex for the response, and the link to the originating source. Based on the Java code it seems that the answers to my three questions are 'yes'. Should they be filed as bugs against the Clojurescript project?

But I think I may see a few more issues with the Java (and CLJS) implementation.

1. `isa?` is a polymorphic comparison regardless of data type: vectors are handled positionally. For `prefers` polymorphism depends on the data type. Vectors are not handled positionally, and calling `parents` on a vector always returns `nil`.

2. On [L88][1] `preferMethod` ensures that there is not already a conflicting prefer in the table. But for the current implementation of `prefers`, switching `x` and `y` is not sufficient. If you first prefer a relationship lower in the lattice, and then a conflicting prefer higher in the lattice, you do not get an error. Reverse the order of operations and you do.

   (def h
     (-> (make-hierarchy)
         (derive ::a ::b)
         (derive ::b ::c)
         (derive ::a ::d)
         (derive ::d ::e)))

   ;; Does not catch conflict
   (defmulti m1 identity :hierarchy #'h)
   (prefer-method m1 ::b ::a)
   (prefer-method m1 ::d ::b)

   ;; Switching order of prefers catches conflict
   (defmulti m2 identity :hierarchy #'h)
   (prefer-method m2 ::d ::b)
   (prefer-method m2 ::b ::a)
   Execution error (IllegalStateException) at user/eval137582 (REPL:244).
   Preference conflict in multimethod 'm2': :user/a is already preferred to :user/b

[1] https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/MultiFn.java#L88