5

I am looking for some code that would look like below:

public class Parent<T is_or_extends Parent<T>> {
    public T function() {
        // do some stuff //
        return correct();
    }
    public T correct() {
        return (T) this;
    }
}

This is so any child classes will have access to the other parent functions, yet will remain independent classes (without upcasting the return value of function() to an instance of Parent). And the programmer can also use the Parent class independently as well (so an instance of Parent can be created without function() downcasting the return object)

Implementation:

public class Child extends Parent<Child> {}

Usage:

Child child = new Child(); // ok
Parent<Child> polymorph = new Child(); // ok
Parent<Parent> parent = new Parent<Parent>(); // ERROR!

Just to outline a difference, this is not an issue with method chaining. Rather when the parent class takes in a generic of a child class, it can no longer be used as a class in its own right (using the code above), because new Parent<Parent>() will not compile (when replacing "is_or_extends" with "extends")

My Goal:

What I am aiming to achieve is a parent class that when extended, function() will return an object of the child class rather than the parent class.

I would use a generic type to tell the parent class which child class called the function, but I can no longer use an object of the parent class itself without experiencing exceptions. An example is below:

public static class Parent<T extends Parent<T>> {}
public static class Child extends Parent<Child> {}

public static void main(String[] args) {
    // This will not compile as Parent cannot extend Parent
    Parent<Parent> parent = new Parent<Parent>();

    // This will work as Child extends Parent
    Child child = new Child();
}

Thanks in advance.

Shuba
  • 376
  • 2
  • 6
  • 14
  • Please clarify some more. You want to be able to use `Parent`? I don't understand your goal. – Sotirios Delimanolis Aug 24 '16 at 22:52
  • Please look at the extension on the question. I can create an object of Child as it extends Parent, but I cannot create an object of Parent. – Shuba Aug 25 '16 at 00:02
  • What I mean by Parent is that the generic type gives the parent class information on which child class object to return in functions. – Shuba Aug 25 '16 at 00:06
  • When using "Parent", the method "function()" in Parent (used at the start) should return an object of Parent. However, Parent does not extend Parent (Parent>), so this will not compile – Shuba Aug 25 '16 at 00:08
  • When using "Parent", the method "function()" in Parent (used at the start) will return an object of Child. – Shuba Aug 25 '16 at 00:08
  • 1
    Try `Parent> parent = new Parent<>();` – shmosel Aug 25 '16 at 00:09
  • For the record, `extends` does mean "is or extends". The reason your example doesn't compile is because the inner `Parent` is a raw type, which is not a valid substitute for `T extends Parent`. – shmosel Aug 25 '16 at 00:12
  • That worked. woop woop. thanks – Shuba Aug 25 '16 at 00:12
  • @SotiriosDelimanolis The question you linked doesn't address how to create an instance of `Pet` (if it weren't abstract), which is OP's question here. – shmosel Aug 25 '16 at 00:15
  • @shmosel It's all yours. I've kind of lost track here. – Sotirios Delimanolis Aug 25 '16 at 00:17
  • Note that the `(T) this` cast is unsafe. `T` is guaranteed to be a subtype of `Parent`, but `Parent` (the type of `this`) may not be a subtype of `T`. – newacct Aug 28 '16 at 06:31

1 Answers1

9

extends does mean "is or extends". The reason your example doesn't compile is because the inner Parent is a raw type, which is not a valid substitute for T extends Parent<T>. The "correct" type would look like this: Parent<Parent<Parent<...>>> ad infinitum. Obviously such a type is impossible to declare.

One solution is to instantiate it like this:

Parent<?> parent = new Parent<>();
Parent<?> derived = parent.function();

This works because the compiler already knows that T is some subclass of Parent<?>. One disadvantage of this trick is that it won't work if the type can't be inferred, for example when using anonymous classes.

Another possible approach - dependent on the nature of parent/child relationship - is to create an additional class to extend the base, just for its type resolution:

// Parent functionality in here
public static abstract class Base<T extends Base<T>> {}

// This can be empty, or have just constructors if necessary
public static class Simple extends Base<Parent> {}

// Child functionality in here
public static class Extended extends Base<Extended> {}
shmosel
  • 49,289
  • 6
  • 73
  • 138