How does clojure.core / compare implement java.util.Comparator?

I saw this code in clojure.core recently.

(defn sort-by
  "Returns a sorted sequence of the items in coll, where the sort
  order is determined by comparing (keyfn item).  If no comparator is
  supplied, uses compare.  comparator must implement
  java.util.Comparator.  If coll is a Java array, it will be modified.
  To avoid this, sort a copy of the array."
  {:added "1.0"
   :static true}
  ([keyfn coll]
   (sort-by keyfn compare coll))
  ([keyfn ^java.util.Comparator comp coll]
   (sort (fn [x y] (. comp (compare (keyfn x) (keyfn y)))) coll)))

      

There is a type hint Comparator

for the argument comp

. But two version arguments sort-by

are passed to it clojure.core/compare

. How it works?

Update:

I would like to know how it clojure.core/compare

implements java.util.Comparator

. compare

as follows:

(defn compare
  "Comparator. Returns a negative number, zero, or a positive number
  when x is logically 'less than', 'equal to', or 'greater than'
  y. Same as Java x.compareTo(y) except it also works for nil, and
  compares numbers and collections in a type-independent manner. x
  must implement Comparable"
  {
   :inline (fn [x y] `(. clojure.lang.Util compare ~x ~y))
   :added "1.0"}
  [x y] (. clojure.lang.Util (compare x y)))

      

Isn't this a normal clojure function?

+3


source to share


2 answers


From jvm/clojure/lang/AFunction.java

:

public abstract class AFunction extends AFn implements IObj, Comparator, Fn, Serializable {

/* ...omitted... */

public int compare(Object o1, Object o2){
        Object o = invoke(o1, o2);

        if(o instanceof Boolean)
                {
                if(RT.booleanCast(o))
                        return -1;
                return RT.booleanCast(invoke(o2,o1))? 1 : 0;
                }

        Number n = (Number) o;
        return n.intValue();
}
}

      



When the Clojure compiler compiles functions, it either implements them as derivatives of RestFn (if variable) or AFunction (otherwise); however RestFn extends AFunction so everything ends up at the same place.

So: all Clojure functions implement Comparator through AFunction, directly or indirectly.

+4


source


UPDATE . Below is my answer based on my confusion as to what was asked: I thought the question was about 3-arity overload instead of 2-arity overload.


I think the confusion comes from the phrase "two arguments of the sort-pass version go clojure.core/compare

to it". This is not true. Look at the code:

(. comp (compare (keyfn x) (keyfn y)))

      



It uses the "exact special form" (see .

as the first item in the list). It is used here as a method call. It will call the method compare

on the instance provided comp

with arguments (keyfn x) (keyfn y)

. clojure.core/compare

There's nothing to do here. Of the various forms of dot expressions, this corresponds to the following case:

(. instance-expr (method-symbol args*))

      

About the type hint: This is just a performance optimization to avoid being reflected in the method call.

+1


source







All Articles