Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Java (http://www.velocityreviews.com/forums/f30-java.html)
-   -   Generics puzzle with implements Comparable (http://www.velocityreviews.com/forums/t615979-generics-puzzle-with-implements-comparable.html)

Roedy Green 05-21-2008 02:17 AM

Generics puzzle with implements Comparable
 
Let's say I have a class

class SalesTaxItem implements Comparable<SalesTaxItem>

And I want to add a field to the this class, and make it Comparable
too.

if I try "class DatedSalesTaxItem extends SalesTaxItem implements
Comparable<DatedSalesTaxItem>"

Then I get this error message:

Comparable cannot be inherited with different arguments.

Is there a way to get both classes comparable?


--

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Owen Jacobson 05-21-2008 03:06 AM

Re: Generics puzzle with implements Comparable
 
On May 20, 10:17*pm, Roedy Green <see_webs...@mindprod.com.invalid>
wrote:
> Let's say I have a class
>
> *class SalesTaxItem implements Comparable<SalesTaxItem>
>
> And I want to add a field to the this class, and make it Comparable
> too.
>
> if I try "class DatedSalesTaxItem extends SalesTaxItem implements
> Comparable<DatedSalesTaxItem>"
>
> Then I get this error message:
>
> Comparable cannot be inherited with different arguments.
>
> Is there a way to get both classes comparable?


If class Foo is comparable to other instances of class Foo, then
subclass Bar of Foo must also be comparable to other instances of
class Foo. Thus, the subclass must also implement Comparable<Foo> --
which it does anyways, via inheritance. You also can't implement the
same interface twice, and two generics specializations of an interface
are actually the same interface under the hood.

You'll have to either do double-dispatch tricks or check which
subclass is involved on the right in the derived class' compareTo
method.

This isn't entirely a generics-related problem. The following might
demonstrate the issue:

class Foo {
public void frobWith(Foo otherFoo) {...}
}

class Bar extends Foo {
public void frobWith(Bar otherBar) {...}
}

The derived class' frobWith method doesn't actually override the
parent class's and won't be called via dynamic dispatch.

Tom Anderson 05-21-2008 11:26 AM

Re: Generics puzzle with implements Comparable
 
On Wed, 21 May 2008, Roedy Green wrote:

> Let's say I have a class
>
> class SalesTaxItem implements Comparable<SalesTaxItem>
>
> And I want to add a field to the this class, and make it Comparable
> too.
>
> if I try "class DatedSalesTaxItem extends SalesTaxItem implements
> Comparable<DatedSalesTaxItem>"
>
> Then I get this error message:
>
> Comparable cannot be inherited with different arguments.


This is a problem with type erasure, and one of the reasons this is a bad
way of doing generics.

> Is there a way to get both classes comparable?


Could you clarify what you want to do? Comparing two SalesTaxItems, fine.
Comparing two DatedSalesTaxItems, fine, i guess. What should happen when
you compare one of one with one of the other? Do you want a SalesTaxItem
to be comparable with a DatedSalesTaxItem? Do you want that to behave the
same as doing the same comparison the other way around?

I was wondering if you could use wildcards for this, but i don't think you
can. You're going to have to do isinstance/cast in the DatedSalesTaxItem
method.

tom

--
I need a proper outlet for my tendency towards analytical thought. --
Geneva Melzack

Roedy Green 05-21-2008 06:35 PM

Re: Generics puzzle with implements Comparable
 
On Wed, 21 May 2008 12:26:23 +0100, Tom Anderson
<twic@urchin.earth.li> wrote, quoted or indirectly quoted someone who
said :

>Could you clarify what you want to do? Comparing two SalesTaxItems, fine.
>Comparing two DatedSalesTaxItems, fine, i guess. What should happen when
>you compare one of one with one of the other? Do you want a SalesTaxItem
>to be comparable with a DatedSalesTaxItem? Do you want that to behave the
>same as doing the same comparison the other way around?


My Comparator Comparables are for sorting collections of either pure
SalesTaxItem or pure DatedSalesTaxItem

I handled it by cloning the code. It is mostly the same except for
adding one field and changing the Comparable to pay attention to the
extra field.


Here is the code cloned.

Ideally it should be rewritten somehow with DatedSalesTaxItem
extending SalesTaxItem.

----------------------------------------------------------------------------------------

package com.mindprod.americantax;

import java.util.Comparator;

/**
* triple country, percent, city
*/
class SalesTaxItem implements Comparable<SalesTaxItem>
{
protected String city;

protected final String county;

protected final double percent;

// -------------------------- PUBLIC INSTANCE METHODS
--------------------------
/**
* constructor
*
* @param county county name
* @param percent tax rate percent including state tax
* @param city city, region of county
*/
public SalesTaxItem( String county, double percent, String city )
{
this.county = county.trim();
this.city = city.trim();
this.percent = percent;
}

public void clearCity()
{
this.city = "";
}

/**
* Compare two Pairs. Callback for natural order sort for
deduping. effectively returns a-b;
*
* @return +1, a>b, 0 a=b, -1 a<b, case insensitive
*/
public final int compareTo( SalesTaxItem o )
{
int diff = this.county.compareTo( o.county );
if ( diff != 0 )
{
return diff;
}
if ( this.percent > o.percent )
{
return 1;
}
if ( this.percent < o.percent )
{
return -1;
}
return this.city.compareTo( o.city );
}// end compareTo

public String getCity()
{
return city;
}

public String getCounty()
{
return county;
}

public String getCountyCity()
{
if ( city == null || city.length() == 0 )
{
return county;
}
else
{
return county + ", " + city;
}
}

public double getPercent()
{
return percent;
}

// -------------------------- INNER CLASSES
--------------------------

/**
* sort triples alphabetically
*/
static final class Alphabetically implements
Comparator<SalesTaxItem>
{
/**
* Compare two triples. sort alphabetically without tax rate
considered. effectively returns b-a;
*
* @return +1, b>a, 0 a=b, -1 b<a, case insensitive
*/
public final int compare( SalesTaxItem o1, SalesTaxItem o2 )
{
int diff = o1.county.compareTo( o2.county );
if ( diff != 0 )
{
return diff;
}

return o1.city.compareTo( o2.city );
}// end compare
}
}

--------------------------------------------------------------------------------------

package com.mindprod.americantax;

import java.util.Comparator;


/**
* country, percent, city, date. Can't extend SalesTaxItem because of
Comparable compatibility.
*/
class DatedSalesTaxItem implements Comparable<DatedSalesTaxItem>
{
private String city;

private final String county;
private final String yyyymmdd;// in form yyyymmdd

private final double percent;

// -------------------------- PUBLIC INSTANCE METHODS
--------------------------
/**
* constructor
*
* @param county county name
* @param percent tax rate percent including state tax
* @param city city, region of county
* @param yyyymmdd date tax came into effect
*/
public DatedSalesTaxItem( String county, double percent, String
city, String yyyymmdd )
{
this.county = county.trim();
this.city = city.trim();
this.percent = percent;
this.yyyymmdd = yyyymmdd;
}

public void clearCity()
{
this.city = "";
}

/**
* Compare two Pairs. Callback for natural order sort for
deduping. effectively returns a-b;
*
* @return +1, a>b, 0 a=b, -1 a<b, case insensitive
*/
public final int compareTo( DatedSalesTaxItem o )
{
int diff = this.county.compareTo( o.county );
if ( diff != 0 )
{
return diff;
}
diff = this.city.compareTo( o.city );
if ( diff != 0 )
{
return diff;
}
diff = this.yyyymmdd.compareTo( o.yyyymmdd );
if ( diff != 0 )
{
return -diff;
}
if ( this.percent > o.percent )
{
return 1;
}
if ( this.percent < o.percent )
{
return -1;
}
return 0;
}// end compareTo

public String getCity()
{
return city;
}

public String getYYYYMMDD()
{
return yyyymmdd;
}

public String getCounty()
{
return county;
}

public String getCountyCity()
{
if ( city == null || city.length() == 0 )
{
return county;
}
else
{
return county + ", " + city;
}
}

public double getPercent()
{
return percent;
}

// -------------------------- INNER CLASSES
--------------------------

/**
* sort triples alphabetically
*/
static final class Alphabetically implements
Comparator<DatedSalesTaxItem>
{
/**
* Compare two triples. sort alphabetically without tax rate
considered. effectively returns b-a;
*
* @return +1, b>a, 0 a=b, -1 b<a, case insensitive
*/
public final int compare( DatedSalesTaxItem o1,
DatedSalesTaxItem o2 )
{
int diff = o1.county.compareTo( o2.county );
if ( diff != 0 )
{
return diff;
}

return o1.city.compareTo( o2.city );
}// end compare
}
}


--

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Roedy Green 05-21-2008 06:37 PM

Re: Generics puzzle with implements Comparable
 
On Wed, 21 May 2008 12:26:23 +0100, Tom Anderson
<twic@urchin.earth.li> wrote, quoted or indirectly quoted someone who
said :

>I was wondering if you could use wildcards for this, but i don't think you
>can. You're going to have to do isinstance/cast in the DatedSalesTaxItem
>method.


Perhaps the best you can do is create a common core without
Comparable, then create two classes that implement Comparable that
extend the core.

--

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com

Tom Anderson 05-22-2008 06:15 PM

Re: Generics puzzle with implements Comparable
 
On Wed, 21 May 2008, Roedy Green wrote:

> On Wed, 21 May 2008 12:26:23 +0100, Tom Anderson
> <twic@urchin.earth.li> wrote, quoted or indirectly quoted someone who
> said :
>
>> Could you clarify what you want to do? Comparing two SalesTaxItems, fine.
>> Comparing two DatedSalesTaxItems, fine, i guess. What should happen when
>> you compare one of one with one of the other? Do you want a SalesTaxItem
>> to be comparable with a DatedSalesTaxItem? Do you want that to behave the
>> same as doing the same comparison the other way around?

>
> My Comparator Comparables are for sorting collections of either pure
> SalesTaxItem or pure DatedSalesTaxItem
>
> I handled it by cloning the code. It is mostly the same except for
> adding one field and changing the Comparable to pay attention to the
> extra field.
>
> Here is the code cloned.
>
> Ideally it should be rewritten somehow with DatedSalesTaxItem extending
> SalesTaxItem.


That's the thing. It can't be. A SalesTaxItem is Comparable<SalesTaxItem>.
If a DatedSalesTaxItem is a SalesTaxItem, then it is also
Comparable<SalesTaxItem>. Them's the rules.

My suggestion would be to forget about Comparable, and write two separate
classes, a Comparator<SalesTaxItem>, and a Comparator<DatedSalesTaxItem>,
to do the job. You have to use them explicitly, but it's typesafe, with no
ickiness.

A type-safe but icky solution would be to equip SalesTaxItem with a
private method String getDate(), hardcoded to return a string indicating
the beginning of time ("19700101"), then to write the comparison method
using the date, as in DatedSalesTaxItem. In DatedSalesTaxItem, you just
have to override the getDate method to return the actual date, and make it
public. You can then declare SalesTaxItem Comparable<SalesTaxItem>, and
all will be well, including in comparisons of mixed kinds of item.

tom

> ----------------------------------------------------------------------------------------
>
> package com.mindprod.americantax;
>
> import java.util.Comparator;
>
> /**
> * triple country, percent, city
> */
> class SalesTaxItem implements Comparable<SalesTaxItem>
> {
> protected String city;
>
> protected final String county;
>
> protected final double percent;
>
> // -------------------------- PUBLIC INSTANCE METHODS
> --------------------------
> /**
> * constructor
> *
> * @param county county name
> * @param percent tax rate percent including state tax
> * @param city city, region of county
> */
> public SalesTaxItem( String county, double percent, String city )
> {
> this.county = county.trim();
> this.city = city.trim();
> this.percent = percent;
> }
>
> public void clearCity()
> {
> this.city = "";
> }
>
> /**
> * Compare two Pairs. Callback for natural order sort for
> deduping. effectively returns a-b;
> *
> * @return +1, a>b, 0 a=b, -1 a<b, case insensitive
> */
> public final int compareTo( SalesTaxItem o )
> {
> int diff = this.county.compareTo( o.county );
> if ( diff != 0 )
> {
> return diff;
> }
> if ( this.percent > o.percent )
> {
> return 1;
> }
> if ( this.percent < o.percent )
> {
> return -1;
> }
> return this.city.compareTo( o.city );
> }// end compareTo
>
> public String getCity()
> {
> return city;
> }
>
> public String getCounty()
> {
> return county;
> }
>
> public String getCountyCity()
> {
> if ( city == null || city.length() == 0 )
> {
> return county;
> }
> else
> {
> return county + ", " + city;
> }
> }
>
> public double getPercent()
> {
> return percent;
> }
>
> // -------------------------- INNER CLASSES
> --------------------------
>
> /**
> * sort triples alphabetically
> */
> static final class Alphabetically implements
> Comparator<SalesTaxItem>
> {
> /**
> * Compare two triples. sort alphabetically without tax rate
> considered. effectively returns b-a;
> *
> * @return +1, b>a, 0 a=b, -1 b<a, case insensitive
> */
> public final int compare( SalesTaxItem o1, SalesTaxItem o2 )
> {
> int diff = o1.county.compareTo( o2.county );
> if ( diff != 0 )
> {
> return diff;
> }
>
> return o1.city.compareTo( o2.city );
> }// end compare
> }
> }
>
> --------------------------------------------------------------------------------------
>
> package com.mindprod.americantax;
>
> import java.util.Comparator;
>
>
> /**
> * country, percent, city, date. Can't extend SalesTaxItem because of
> Comparable compatibility.
> */
> class DatedSalesTaxItem implements Comparable<DatedSalesTaxItem>
> {
> private String city;
>
> private final String county;
> private final String yyyymmdd;// in form yyyymmdd
>
> private final double percent;
>
> // -------------------------- PUBLIC INSTANCE METHODS
> --------------------------
> /**
> * constructor
> *
> * @param county county name
> * @param percent tax rate percent including state tax
> * @param city city, region of county
> * @param yyyymmdd date tax came into effect
> */
> public DatedSalesTaxItem( String county, double percent, String
> city, String yyyymmdd )
> {
> this.county = county.trim();
> this.city = city.trim();
> this.percent = percent;
> this.yyyymmdd = yyyymmdd;
> }
>
> public void clearCity()
> {
> this.city = "";
> }
>
> /**
> * Compare two Pairs. Callback for natural order sort for
> deduping. effectively returns a-b;
> *
> * @return +1, a>b, 0 a=b, -1 a<b, case insensitive
> */
> public final int compareTo( DatedSalesTaxItem o )
> {
> int diff = this.county.compareTo( o.county );
> if ( diff != 0 )
> {
> return diff;
> }
> diff = this.city.compareTo( o.city );
> if ( diff != 0 )
> {
> return diff;
> }
> diff = this.yyyymmdd.compareTo( o.yyyymmdd );
> if ( diff != 0 )
> {
> return -diff;
> }
> if ( this.percent > o.percent )
> {
> return 1;
> }
> if ( this.percent < o.percent )
> {
> return -1;
> }
> return 0;
> }// end compareTo
>
> public String getCity()
> {
> return city;
> }
>
> public String getYYYYMMDD()
> {
> return yyyymmdd;
> }
>
> public String getCounty()
> {
> return county;
> }
>
> public String getCountyCity()
> {
> if ( city == null || city.length() == 0 )
> {
> return county;
> }
> else
> {
> return county + ", " + city;
> }
> }
>
> public double getPercent()
> {
> return percent;
> }
>
> // -------------------------- INNER CLASSES
> --------------------------
>
> /**
> * sort triples alphabetically
> */
> static final class Alphabetically implements
> Comparator<DatedSalesTaxItem>
> {
> /**
> * Compare two triples. sort alphabetically without tax rate
> considered. effectively returns b-a;
> *
> * @return +1, b>a, 0 a=b, -1 b<a, case insensitive
> */
> public final int compare( DatedSalesTaxItem o1,
> DatedSalesTaxItem o2 )
> {
> int diff = o1.county.compareTo( o2.county );
> if ( diff != 0 )
> {
> return diff;
> }
>
> return o1.city.compareTo( o2.city );
> }// end compare
> }
> }
>
>
>


--
They didn't have any answers - they just wanted weed and entitlement.

Roedy Green 05-22-2008 08:41 PM

Re: Generics puzzle with implements Comparable
 
On Thu, 22 May 2008 19:15:00 +0100, Tom Anderson
<twic@urchin.earth.li> wrote, quoted or indirectly quoted someone who
said :

>My suggestion would be to forget about Comparable, and write two separate
>classes, a Comparator<SalesTaxItem>, and a Comparator<DatedSalesTaxItem>,


That is what I have written up as the way around this. Thanks for your
solution.

See http://mindprod.com/jgloss/comparable.html
--

Roedy Green Canadian Mind Products
The Java Glossary
http://mindprod.com


All times are GMT. The time now is 02:37 PM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.