Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > Comparables and Generics

Reply
Thread Tools

Comparables and Generics

 
 
Josef Garvi
Guest
Posts: n/a
 
      04-28-2005
How do I express "A Comparable that can be compared to itself" in generics?

I have a method that takes as parameter an array of Comparables.
Whilst trying to "modernize" this code, I can no longer write simply:

public void myMethod(Comparable[] primaryKeyValues)

but need to add "generic info" to Comparable.
The only requirement I have is that the objects should be able to run a
compareTo() on an instance of their own classes.

--
Josef Garvi

"Reversing desertification through drought tolerant trees"
http://www.eden-foundation.org/

new income - better environment - more food - less poverty
 
Reply With Quote
 
 
 
 
pole
Guest
Posts: n/a
 
      04-28-2005
Josef Garvi wrote:
> How do I express "A Comparable that can be compared to itself" in generics?
>
> I have a method that takes as parameter an array of Comparables.
> Whilst trying to "modernize" this code, I can no longer write simply:
>
> public void myMethod(Comparable[] primaryKeyValues)


Do you mean taking an array of Comparable of a speficic type?
This is a declaration for a method which takes an array of Comparable<T>
instances:

public <T> void myMethod( Comparable<T>[] primaryKeyValues )

pole

--
ammentos - a lightweight persistence framework for JDK5
http://www.sourceforge.net/projects/ammentos
http://ammentos.biobytes.it
 
Reply With Quote
 
 
 
 
John C. Bollinger
Guest
Posts: n/a
 
      04-28-2005
Josef Garvi wrote:

> How do I express "A Comparable that can be compared to itself" in generics?
>
> I have a method that takes as parameter an array of Comparables.
> Whilst trying to "modernize" this code, I can no longer write simply:
>
> public void myMethod(Comparable[] primaryKeyValues)
>
> but need to add "generic info" to Comparable.
> The only requirement I have is that the objects should be able to run a
> compareTo() on an instance of their own classes.
>


The signature

public <T extends Comparable<T>> void myMethod(T[] primaryKeyValues)

should do the trick. That reads in English something like "a public
method making use of a type, T, that is comparable to itself; returning
no result; and taking as a parameter an array of objects of the
aforementioned type T."

For utmost generality, however, you would want

public <T extends Comparable<? super T>> void myMethod(T[] primaryKeyValues)

which differs from the first example in that it allows key types that
are Comparable to a superclass of their own class. This allows more
types for the keys while still ensuring that all the array elements are
mutually comparable.


--
John Bollinger
http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
Josef Garvi
Guest
Posts: n/a
 
      04-28-2005
pole wrote:
> Josef Garvi wrote:
>
>> How do I express "A Comparable that can be compared to itself" in
>> generics?
>>
>> I have a method that takes as parameter an array of Comparables.
>> Whilst trying to "modernize" this code, I can no longer write simply:
>>
>> public void myMethod(Comparable[] primaryKeyValues)

>
>
> Do you mean taking an array of Comparable of a speficic type?
> This is a declaration for a method which takes an array of Comparable<T>
> instances:
>
> public <T> void myMethod( Comparable<T>[] primaryKeyValues )
>
> pole


Will all the Comparables in primaryKeyValues now have to be of the same
class, or can they be of varying classes (within the same array instance).

I would like to call it like this:

myMethod(new Comparable[] {new Integer(12), new String("Good morning")});

I use Comparable[] rather than Object[] as argument, as each value in the
array should be possible to compare with other values, but only other
values of the same type as itself. (meaning the String will never be
compared to an Integer).


--
Josef Garvi

"Reversing desertification through drought tolerant trees"
http://www.eden-foundation.org/

new income - better environment - more food - less poverty
 
Reply With Quote
 
Josef Garvi
Guest
Posts: n/a
 
      04-28-2005
John C. Bollinger wrote:

> For utmost generality, however, you would want
>
> public <T extends Comparable<? super T>> void myMethod(T[]
> primaryKeyValues)
>
> which differs from the first example in that it allows key types that
> are Comparable to a superclass of their own class. This allows more
> types for the keys while still ensuring that all the array elements are
> mutually comparable.


Whooh, the syntax is overwhelming!
Thanks.

How can I now store the primaryKeyValues into a field of my class?
For example, I'm not allowed to write:

private Comparable<T extends Comparable<? super T>>[] keyValues;


I'm getting the impression that using the function compareTo was a whole
lot easier before Generics...

--
Josef Garvi

"Reversing desertification through drought tolerant trees"
http://www.eden-foundation.org/

new income - better environment - more food - less poverty
 
Reply With Quote
 
John C. Bollinger
Guest
Posts: n/a
 
      04-28-2005
pole wrote:

> Josef Garvi wrote:
>
>> How do I express "A Comparable that can be compared to itself" in
>> generics?
>>
>> I have a method that takes as parameter an array of Comparables.
>> Whilst trying to "modernize" this code, I can no longer write simply:
>>
>> public void myMethod(Comparable[] primaryKeyValues)

>
>
> Do you mean taking an array of Comparable of a speficic type?


He was pretty clear, I thought, about "a comparable that can be compared
to itself". This keys on the concept, formalized with generics, that
Comparables are not all comparable to each other, with the implicit
corollary that a particular Comparable is not necessarily even
comparable to itself.

The original declaration translates directly to generics as

public void myMethod(Comparable<?>[] primaryKeyValues)

but that does not achieve what he wants, because it does not constrain
what the Comparables are comparable _to_.

> This is a declaration for a method which takes an array of Comparable<T>
> instances:
>
> public <T> void myMethod( Comparable<T>[] primaryKeyValues )


That is a little better in that it ensures that the Comparables are all
comparable to the same type, and it also makes that type accessible in
the method body via the type parameter. It does not, however, ensure
that the type T implements Comparable at all, much less Comparable<T>.
See my response to the OP for two related solutions that do solve the
problem.

--
John Bollinger
(E-Mail Removed)
 
Reply With Quote
 
Josef Garvi
Guest
Posts: n/a
 
      04-28-2005
To clarify things a bit:
What I'm trying to do is to convert the following class so that it works
with Generics (and thus does not cause a compiler warning anymore):


public class ComplexKey implements Comparable<ComplexKey> {

private Comparable[] keyValues;

public ComplexKey(Comparable[] keyValues) {
super();
this.keyValues = keyValues;
}

public int compareTo(ComplexKey compareWith) {
if (compareWith.keyValues.length == keyValues.length) {
for (int i = 0; i < keyValues.length; i++) {
int x =
keyValues[i].compareTo(compareWith.keyValues[i]); // <- WARNING
if (x != 0) return x;
}
return 0;
} else
throw new ClassCastException("Number of key values do not match.");
}

[...a few other methods...]

}

The purpose of the class is to contain the primary key values of a database
record so it can be used as key in a HashMap.

I get a pesky warning about not being type safe on the line indicated with
the comment, and I can't completely figure out how to rebuild my class:
"Type safety: The method compareTo(Object) belongs to the raw type
Comparable. References to generic type Comparable<T> should be
parameterized"


--
Josef Garvi

"Reversing desertification through drought tolerant trees"
http://www.eden-foundation.org/

new income - better environment - more food - less poverty
 
Reply With Quote
 
John C. Bollinger
Guest
Posts: n/a
 
      04-28-2005
Josef Garvi wrote:

> To clarify things a bit:
> What I'm trying to do is to convert the following class so that it works
> with Generics (and thus does not cause a compiler warning anymore):
>
>
> public class ComplexKey implements Comparable<ComplexKey> {
>
> private Comparable[] keyValues;
>
> public ComplexKey(Comparable[] keyValues) {
> super();
> this.keyValues = keyValues;
> }
>
> public int compareTo(ComplexKey compareWith) {
> if (compareWith.keyValues.length == keyValues.length) {
> for (int i = 0; i < keyValues.length; i++) {
> int x =
> keyValues[i].compareTo(compareWith.keyValues[i]); // <- WARNING
> if (x != 0) return x;
> }
> return 0;
> } else
> throw new ClassCastException("Number of key values do not match.");
> }
>
> [...a few other methods...]
>
> }
>
> The purpose of the class is to contain the primary key values of a
> database record so it can be used as key in a HashMap.
>
> I get a pesky warning about not being type safe on the line indicated
> with the comment, and I can't completely figure out how to rebuild my
> class:
> "Type safety: The method compareTo(Object) belongs to the raw type
> Comparable. References to generic type Comparable<T> should be
> parameterized"


Before you can solve the problem, you have a fundamental question to
answer: what type are the specific key values supposed to be comparable
to? You can describe the type by means of a type parameter, if you
like, in which case you will need to make the ComplexKey class generic,
with the appropriately chosen type parameter. It might look like this:

public class ComplexKey <T extends Comparable<T>>
implements Comparable<ComplexKey<T>> {

private T[] keyValues;

[...]

public int compareTo(ComplexKey<T> compareWith) {
[...]
int x = keyValues[i].compareTo(compareWith.keyValues[i]);
[...]
}
}


I suspect, however, that you still have a problem: the key values'
classes in that scheme are going to need to all inherit from (or be) a
common superclass that is Comparable to itself, because putting them all
in the same array requires that they all have types compatible with the
element type of the array. If I am correctly inferring your use of this
class, then this is a fundamental type safety problem with your
approach. (In the sense that its type safety cannot be verified by
compile-time checks.)

--
John Bollinger
(E-Mail Removed)
 
Reply With Quote
 
Josef Garvi
Guest
Posts: n/a
 
      04-29-2005
John C. Bollinger wrote:
>
> Before you can solve the problem, you have a fundamental question to
> answer: what type are the specific key values supposed to be comparable
> to?


A single instance of ComplexKey might hold something like: a String, an
Integer and a Double. Simply put, the type of values you could find in the
fields of a primary key in a relational db.


> You can describe the type by means of a type parameter, if you
> like, in which case you will need to make the ComplexKey class generic,
> with the appropriately chosen type parameter. It might look like this:
>
> public class ComplexKey <T extends Comparable<T>>
> implements Comparable<ComplexKey<T>> {
>
> private T[] keyValues;
>
> [...]
>
> public int compareTo(ComplexKey<T> compareWith) {
> [...]
> int x = keyValues[i].compareTo(compareWith.keyValues[i]);
> [...]
> }
> }
>
>
> I suspect, however, that you still have a problem: the key values'
> classes in that scheme are going to need to all inherit from (or be) a
> common superclass that is Comparable to itself, because putting them all
> in the same array requires that they all have types compatible with the
> element type of the array. If I am correctly inferring your use of this
> class, then this is a fundamental type safety problem with your
> approach. (In the sense that its type safety cannot be verified by
> compile-time checks.)


Yes, I think you're correct here.
A single instance of the ComplexKey can hold several different types in its
array, with the only common denominator being that they are comparable to
their own types - not to each other.

They all must implement Comparable, because otherwise the ComplexKey itself
can't become Comparable. (So changing the signature to accepting an array
of Objects would not be satisfactory).

Basically, the ComplexKey class is used for caching record keys from db
tables. In practice, this means that ComplexKeys are compared with other
ComplexKeys built with records from the same table (same order of class
instances in the keyValues array). To be more concrete, an instance of
ComplexKey holding a reference to a record in table "Orders" will only be
compared to other ComplexKeys referencing that same table, "Orders", never
to records in a table "Farmers". Attempting this would most likely throw a
run-time error, as two different tables are likely to have different types
of primary keys.

Does this mean that I should create a subclass of ComplexKey for every
possible combination of field types in the primary key? Rather than
accepting an array with field values, each subclass would have a different
constructor:

public ComplexKey(Integer farmerId)
public ComplexKey(Integer farmerId, Integer Year, Integer speciesId)

This would create an explosion of classes and seems like a lot of work...
And seem a lot less "generic" than what I'm doing today!

--
Josef Garvi

"Reversing desertification through drought tolerant trees"
http://www.eden-foundation.org/

new income - better environment - more food - less poverty
 
Reply With Quote
 
Chris Uppal
Guest
Posts: n/a
 
      04-29-2005
Josef Garvi wrote:

> Basically, the ComplexKey class is used for caching record keys from db
> tables. In practice, this means that ComplexKeys are compared with other
> ComplexKeys built with records from the same table (same order of class
> instances in the keyValues array). To be more concrete, an instance of
> ComplexKey holding a reference to a record in table "Orders" will only be
> compared to other ComplexKeys referencing that same table, "Orders", never
> to records in a table "Farmers". Attempting this would most likely throw a
> run-time error, as two different tables are likely to have different types
> of primary keys.


Then attempting to force static type checking using generics strikes me as a
massive waste of time. You are /only/ arguing with the compiler about whether
you know what you are doing, not producing productive code.

I'd treat everything as Objects; let generics go hang. Stick some type
assertions in to make the design more self-documenting and to aid debugging if
you feel you need it.

-- chris




 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
generics depending on generics Soul VHDL 0 02-02-2009 09:14 AM
Generics syntax and Comparing Comparables of type ? Sideswipe Java 12 07-26-2007 12:39 AM
Generics and associative array of keys and diverse objects Frank Fredstone Java 1 09-19-2006 11:42 AM
tutorial on generics and threads and io puzzlecracker Java 7 01-31-2006 03:38 PM
Can't convert a generics list of objects into a generics list ofinterfaces Juergen Berchtel Java 1 05-20-2005 02:07 PM



Advertisments