views:

153

answers:

4
+1  Q: 

Generic return

Hi,

there is an immutable class:

Scope<Cmp extends Comparable<Cmp>>
public Scope<Cmp> crop(Scope<Cmp> scope) {
    ...
    return new Scope<Cmp>(starts, ends);
}

it has many similar methods is extended by:

Timerange extends Scope<Date>

and many others (also immutable).

Id like them to return object of its type. For example:

timerange.crop(scope)

should return Timerange object, not Scope.

Do I have to override every method (or use reflection)? Is there another way of doing this?

Thanks in advance, Etam.

+2  A: 

Java doesn't have self-type returns, so you generally need to manually override every method. See http://www.jroller.com/scolebourne/entry/java_7_self_types for a discussion with some possible alternatives.

JodaStephen
+2  A: 

You could try the following:

class Scope<Cpm extends Comparable<Cpm>, Derived extends Scope<Cpm, Derived>> {
  public Derived crop(Scope<Cmp, Derived> scope)
}

TimeRange would be defined as

class TimeRange extends Scope<Date, Timerange>

and so crop would return a TimeRange object. When the deriving class is undefined, you can use generic wildcards (Scope<Date, ?>)

Dario
But there is no way to create an object of a generic type.
newacct
Then an abstract creator method must be implemented.
Dario
+4  A: 

You need some kind of factory. In this case factory method works fine.

public abstract class Scope<E extend Comparable<E>> {
    abstract Scope<E> create(E start, E end);

    public Scope<E> crop(Scope<E> scope) {
        ...
        return create(starts, ends);
    }
}
public TimeRange extends Scope<Date> {
    Scope<Date> create(Date start, Date end) {
        return new TimeRange (...);
    }
}

You may want to add a generic 'this' parameter to the base class:

public abstract class Scope<THIS extends Scope<THIS, E>, E extend Comparable<E>> {
    abstract THIS create(E start, E end);

    public THIS crop(Scope<E> scope) {
        ...
        return create(starts, ends);
    }
}
public TimeRange extends Scope<TimeRange,Date> {
    TimeRange create(Date start, Date end) {
        return new TimeRange (...);
    }
}

This does add extra work to the client code.

Tom Hawtin - tackline
A: 

Do you really need Timerange? Does it offer anything more than just Scope<Date>? If not, then just use Scope<Date>.

Another suggestion is that maybe, instead of instantiating it using the constructor, you can clone the object, and then modify the fields appropriately for the new object. The reason is that the cloned object is the same type as the original.

Scope<Cmp extends Comparable<Cmp>> implements Cloneable
public Scope<Cmp> crop(Scope<Cmp> scope) {
    ...
    Scope<Cmp> result = (Scope<Cmp>)super.clone();
    result.init(starts, ends); // sets the fields for a cloned object
                               // init() could be private
    return result;
}
newacct