On 2020-04-20 21:19, Joe Darcy wrote:
Hello,

On 4/16/2020 5:47 AM, Magnus Ihse Bursie wrote:
[snip]
The tricky one here is the helper TableModelComparator. This one took me a while to wrap my head around. It implements Comparator, but the compare() method takes "rows" from the model, which are just expressed as Objects, and left to subclasses to define differently. For one of the subclasses it uses the type T that the TableModel is created around, but in other it uses an independent domain model. :-/ Anyway. The compare() method then extracts data for the individual columns of each row using the method getValueForColumn(), and compare them pairwise. This data from the rows are supposed to implement Comparable.

In the end, I think I got it pretty OK, but I'm still an apprentice when it comes to generics black magic. The subclasses of TableModelComparator want to return different objects from getValueForColumn() for different columns in the row, like Long or String. They are all Comparable, but String is Comparable<String> and Long is Comparable<Long>. So I needed to specify the abstract method as returning Comparable<?>, since Comparable<String> is not Comparable<Object>.

But then, for reasons that I do not fully fathom, I could not specify

Comparable<?> o1 = getValueForColumn(row1, columns[i]);
Comparable<?> o2 = getValueForColumn(row2, columns[i]);
int result = o1.compareTo(o2);

because the compiler did not accept the call to compareTo().

I did try to sacrifice a black rooster at midnight and walking backwards in a circle three time, to no avail. Maybe the problem was that it was not full moon or that I have no cat. In the end, I casted o1 and o2 to Comparable<Object> and suppressed the warning for that cast.

If anyone knows what rituals I need to perform to make this work, or -- even better -- how to fix the code properly, please let me know!

A brief discussion of wildcards, ?. The meaning of a wildcard is some particular unknown type, meeting the various  constraints from "? extends" or "? super".  If there is no explicit constraint listed, it is equivalent to "? extends Object".

So the meaning of the code above is something

Comparable<S> o1 = getValueForColumn(row1, columns[i]);
Comparable<T> o2 = getValueForColumn(row2, columns[i]);

where S and T are two fresh, unrelated type variables. Concretely, this means S and T could be, say, String and Integer so that is why a call to o1.compareTo(o2) would not be accepted by the compiler since Strings and Integer aren't comparable to each other.

Ah, right, and compareTo -- in contrast with equals() -- only compares to objects of the same type. I think that's part of what confused me here.

While two instances of "Comparable<?>" are syntactically the same, they don't represent the same type inside the compiler.

In some cases, you can get around this issue by using a separate method to capture the type variable and then use it more than once. A technique we've used in the JDK is to have a pubic method with a wildcards calling a private method using a type variable. I've looked around for a few minutes and didn't find a concrete example in the JDK, but they're in there.

I haven't looked over the specific code here in much detail; the type Comparable<Object> might to be the best you can do, but it isn't very expressive since Object's aren't necessarily comparable.
Thank you for taking time to explain this!

/Magnus

HTH,

-Joe


Reply via email to