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 Comparator
type hint on the argument comp
. But the two argument version of sort-by
passes clojure.core/compare
to it. How does this work?
Update:
I would like to know how clojure.core/compare
implements java.util.Comparator
. compare
looks like this:
(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)))
Isnt't this just a normal clojure function?
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 is compiling functions, it either implements them as derivatives of RestFn (if variadic) or AFunction (otherwise); however, RestFn extends AFunction, so it all ends up at the same place.
So: All Clojure functions implement Comparator through AFunction, either directly or indirectly.