tags:

views:

230

answers:

5

I have the following situation :

abstract class X { abstract X someMethod (...) {...} }.

Now I want to constrain any implementation of X to have its 'someMethod' method return that particular implementation type, not just X :

class X1 extends X { X1 someMethod (...) {...} }.
class X1 extends X { X someMethod (...) {...} }.  //want this to be flagged as an error
class X2 extends X { X1 someMethod (...) {...} }.  //want this to be flagged as an error too

Is it possible to achieve this using Java generics ?

EDIT

Okay. I only asked the yes/no question and got a "yes". My fault. What I was actually interested in is "how do I write the declarations".

+1  A: 

Yes. This is return type covariance.

uckelman
He is not asking whether a covariant return type is permitted. He is asking how to enforce it ...
meriton
A: 

This should work just fine:

class X<T> {
  abstract T someMethod(...);
}

class X1<T1> extends X
  T1 someMethod(...) {
    ...
  }
}
Robert J. Walker
+1  A: 
abstract class X<I extends X<I>> {
    protected X(Class<I> implClazz) {
        if (!getClass().equals(implClazz)) {
            throw new IllegalArgumentException();
        }
    }

    abstract I someMethod();
}

Rationale: You can not refer to the dynamic type in type bounds, hence the indirect check in the constructor.

meriton
Many thanks, very helpful.Would have upvoted this, but I get a "Please login or register" response.
Erwin Smout
Is your rationale why Bjorn's solution still allows me to write"class X2 extends X<X1> {X1 someMethod () {...}}"
Erwin Smout
Exactly. The constructor's only purpose is to guard against that.
meriton
I noticed that by testing in the mean time. However. your solution is essentially exposed to the same problem, because nothing prevents an implementor from writing an X2 constructor invoking, say, "super(X1.class)".So I have concluded that the definitive answer to my question is "No, not quite". Still many thanks nevertheless.
Erwin Smout
Yes, there is no way to statically enforce this. You can enforce it at runtime, though.
meriton
My example that makes Bjorn's solution fail is somewhat contrived, and what makes your solution fail is even more so. I'm going to have to contemplate on whether to implement this.
Erwin Smout
+2  A: 

This works as well;

abstract class X<T> {
    public abstract T yourMethod();
}
class X1 extends X<X1> {
    public X1 yourMethod() {
        return this;
    }
}
class X2 extends X<X2> {
    public X2 yourMethod() {
        return this;
    }
}
Björn
Many thanks, very helpful.Would have accepted this, but I get a "Please login or register" response.
Erwin Smout
I consider this to be very ugly code, but it's also the only solution I know of, and I'm guilty of using it myself... +1
rmeador
On second thought ... does anybody know for sure that this is a feature of Jav
Erwin Smout
... of Java generics, and not just a hazardous byproduct of the way they were conceived/implemented ?
Erwin Smout
This solution allows a subclass implementor to write: class X3 extends X<String>, which is probably not your intention...
meriton
A: 

Here's an approach that lets you return a parameter type for this:

AbstractFoo<T extends AbstractFoo<T>> {
  /** Subclasses must implement to return {@code this}. */
  protected abstract T getThis();

  /**  Does something interesting and returns this Foo */
  public T inheritedThing {
    /* blah di blah */
    return getThis();
  }
} 
rjrjr