Is Comparator a type class?

后端 未结 3 885
野趣味
野趣味 2021-02-08 02:55

I\'ve been reading up on type classes in Scala and thought I had a good grasp on it, until I remembered Java\'s java.util.Comparator.

If I understand proper

3条回答
  •  爱一瞬间的悲伤
    2021-02-08 03:08

    The term type class comes from Haskell were they are part of the language. In scala, it is not, it is more of a pattern, which happens to have a lot of language support in scala (implicits, mostly). The pattern makes sense even without this syntactic support, for instance in java, and I would say that Comparator is a typical example of that pattern there (although the term type class is not used in java).

    From an object oriented perspective, the pattern consist in having Comparator rather than Comparable. The most basic object thinking would have the comparison service in the object, say class String implements Comparable. However, extracting it has numerous advantages:

    • You can provide the service for a class whose code you cannot change (for instance, arrays)
    • You can provide different implementation of the service (there are zillion ways to compare strings (case insensitive and a lot of language dependent one). People may be sorted by their name, their age, whatever. And also, you may simply want an ordering reversed.

    These two reasons are enough to have Comparable in java, and to use them in in sorted collections (e.g TreeSet) Comparable is kept, as it gives a convenient default (no need to pass a Comparator when you want the "default" comparison, and it is easier to call (x.compareTo(y) rather than comparator.compare(x,y)). In scala, with implicits, none of this reason is compelling (interoperability with java would still be a reason to implement Ordered/Comparable in scala).

    There are other, less obvious advantages to type classes. Among them :

    • A type class implementation is available and may be useful even when you have no instance of the type it operates on. Consider the operation sum(list). It requires that there is some sort of addition available on the elements of the list. This might be available in the element themselves. Say they could be some Addable[T] with def add(other: T): T. But if you pass the empty list to sum, it should return the "zero" of the type of the type of the list (0 for ints, the empty string for strings...). Having a def zero: T in Addable[T] would be useless, as at that moment, you have no Addable around. But this works fine with a type class such as Numeric or Monoid.
    • As the type class are reified (they are objects rather than methods) they are first class, you can combine them, transform them. A very simple example is reversing an Ordering (you could implement that on Comparable too, in java probably in a static method). You can combine the ordering of Int and String to have an ordering defined on the pair (Int, String), or given an Ordering on T, build an ordering on List[T]. Scala does that with implicits, but it still makes sense in java, explicitly.

    A more sophisticated example:

    // Comparison  by the first comparator which finds the two elements different. 
    public static Comparator lexicographic(final Comparator... comparators) {
       return new Comparator() {
          public int compare(T t1, T t2) {
             for(comparator : comparators) {
                int result = comparator.compare(t1, t2);
                if (result != 0) return result;
             }
             return 0;
          }
       }
    }
    

    (might be simpler in scala, but again, this is of interest in java)

    There are some small disadvantages too (much more so in java than in scala, but still)

    • You must pass around the type class instance from method to method. Much easier in scala with implicit parameter, or the [T : Comparable] constraint, but still, something has to be written in the methods definitions if not at call site, and at run time, the parameter has to be passed around.
    • Everything must be set at compile time (even in scala where it is set implicitly So while you can try if(x is Comparable) {do some sorting}, this would not be possible with a Comparator.

提交回复
热议问题