Interface output in Java

I have been working with Java recently and have been wondering if there is any conclusion to the interface implementation in Java. My preferred programming language is Haskell, which largely contradicts Java, but one feature I was wondering about is whether Java has something like the ability to infer interface implementations of complex types from an interface implementation of their parameters. For example, in Haskell:

data Pair kv = Pair kv instance (Ord k) => Ord (Pair kv) where compare (Pair x _) (Pair x' _) = compare xx' 

This allows you to order a Pair if its first parameter can be ordered, without the explicit requirement that this be so. However, the closest I can come to this in Java is through an explicit requirement:

 class Pair<K extends Comparable<K>, V> extends Comparable<Pair<K,V>> { K k; V v; public int compareTo(Pair<K,V> p) { return k.compareTo(pk); } } 

Without the opportunity to leave the possibility of matching, it is impossible for me to implement BST pairs without guaranteeing that all pairs have a comparable first element, so I cannot implement any kind of Map where the first element is not explicitly required to be comparable. Is there any way around this other than creating a method of my BST class that tries to compare a generic type, discarding it first as comparable and then as pairs with a comparable key, comparing when compatibility is possible?

+5
source share
3 answers

It's impossible. Java does not have a type mechanism; Java interfaces are just vaguely reminiscent of type classes, but lack the means to automatically create an interface (among other, more fundamental differences from type classes). The type either implements or does not implement the interface - there is no way to make the type magically inherited at compile time, something that it no longer has, and not to make the stop type inherit from what it no longer does.

It is also not possible to move the constraint to compareTo , since this should have happened when defining compareTo inside Comparable .

I would be glad that someone would prove to me that I was wrong.

The closest you get to the JVM-style Haskell type classes are: Scala and the Frege - Scala implicit resolution mechanism is in some ways even more powerful / expressive than Haskell, but also more detailed and has some fundamental WRT limitations while simultaneously using existence and type restrictions; Frege is just a Haskell clone for the JVM.


Workaround:

Besides the Java-specific / task-specific, possibly template-based and partial, workaround, the closest I know about is an explicit re-implementation of type classes (this is just a specific term / implementation of Haskell ad-hoc polymorphism ).

A question related to bayou.io will help you get started (although it's pretty simple): Limited interface implementation . The output of an instance of a class class should also happen explicitly - you won't get any of the type levels, autoscaling compilation time that you get in Haskell or Scala or similar, but you still get the flexibility and (most?) Static checking.

PS Some Haskellers believe that this should be done even in Haskell, so this can give you an idea or three: http://www.haskellforall.com/2012/05/scrap-your-type-classes.html .

+4
source

In Java, it is often better to have some kind of “companion” interface or class for this kind of problem. In a sense, these satellites are much closer to the Haskell class classes than something built with inheritance. For comparison, this "companion" Comparator . One of the advantages is that you can sort one class (say Person) with different comparators (for example, one for the name, one for the age ...). In your case, the companion approach also solves that the problem of “generics should be more specific for this job”:

 public class Pair<K, V> { final public K k; final public V v; public Pair(K k, V v) { this.k = k; this.v = v; } } public class PairComparator<K extends Comparable<? super K>, V> implements Comparator<Pair<K,V>> { @Override public int compare(Pair<K, V> o1, Pair<K, V> o2) { return o1.k.compareTo(o2.k); } } //works for any Pairs with comparable keys: PairComparator<String, Integer> comp = new PairComparator<String, Integer>(); Pair<String, Integer> p1 = new Pair<>("z",1); Pair<String, Integer> p2 = new Pair<>("a",3); System.out.println(comp.compare(p1,p2)); 
+2
source

You can create two different Pair classes, for example:

 public class Pair<K, V> { protected final K key; protected final V value; public Pair(K key, V value) { this.key = key; this.value = value; } } public class ComparablePair<K extends Comparable<K>, V> extends Pair<K, V> implements Comparable<ComparablePair<K, V>> { public ComparablePair(K key, V value) { super(key, value); } @Override public int compareTo(ComparablePair<K, V> o) { return key.compareTo(o.key); } } 

And limit Comparable trees to a second class. However, it looks cleaner (especially in Java-8) to use a disparate pair, but specify Comparator instead:

 class MyTree<K, V> { final Comparator<K> comparator; public MyTree(Comparator<K> comparator) { this.comparator = comparator; } ... instead of k1.compareTo(k2) use comparator.compare(k1, k2) ... } 

Thus, you achieve greater flexibility, since you can compare keys not only in the natural order, but also for any order. If you need a natural order, just use new MyTree<String, Integer>(Comparator.naturalOrder()); . This way you will have a compile time check to see if your key type is comparable.

0
source

Source: https://habr.com/ru/post/1232673/


All Articles