Method Chaining + Inheritance Don't Play Well Together

Method chaining + inheritance don't play well together?

For the second problem, making setAngle virtual should do the trick.

For the first one, there are no easy solutions. Widget::move returns a Widget, which doesn't have a setText method. You could make a pure virtual setText method, but that'd be a pretty ugly solution. You could overload move() on the button class, but that'd be a pain to maintain. Finally, you could probably do something with templates. Perhaps something like this:

// Define a move helper function
template <typename T>
T& move(T& obj, Point& p){ return obj.move(p); };

// And the problematic line in your code would then look like this:
move(btn, Point(0,0)).setText("Hey");

I'll let you decide which solution is cleanest. But is there any particular reason why you need to be able to chain these methods?

Method chaining + inheritance don’t play well together?

If you want to avoid unchecked cast warnings from your compiler (and don't want to @SuppressWarnings("unchecked")), then you need to do a little more:

First of all, your definition of Pet must be self-referential, because Pet is always a generic type:

abstract class Pet <T extends Pet<T>>

Secondly, the (T) this cast in setName is also unchecked. To avoid this, use the "getThis" technique in the excellent Generics FAQ by Angelika Langer:

The "getThis" trick provides a way to
recover the exact type of the this
reference.

This results in the code below, which compiles and runs without warnings. If you want to extend your subclasses, then the technique still holds (though you'll probably need to genericise your intermediate classes).

The resulting code is:

public class TestClass {

static abstract class Pet <T extends Pet<T>> {
private String name;

protected abstract T getThis();

public T setName(String name) {
this.name = name;
return getThis(); }
}

static class Cat extends Pet<Cat> {
@Override protected Cat getThis() { return this; }

public Cat catchMice() {
System.out.println("I caught a mouse!");
return getThis();
}
}

static class Dog extends Pet<Dog> {
@Override protected Dog getThis() { return this; }

public Dog catchFrisbee() {
System.out.println("I caught a frisbee!");
return getThis();
}
}

public static void main(String[] args) {
Cat c = new Cat();
c.setName("Morris").catchMice();
Dog d = new Dog();
d.setName("Snoopy").catchFrisbee();
}
}

Method chaining + inheritance 2 or more times

The problem is that you had a lot of "raw" type in your definitions, e.g.

Vec2 < C extends Vec2 >
----
raw type!

After a few rounds, you'll reach a raw type, and erasure makes C the same as Vec2.


We can do the following, using type variable This as the "self type"

public class Vec2<This> {

public This add(double x, double y) {
this.x += x;
this.y += y;
return (This) this;
}

}

public class Vec3<This> extends Vec2<This> {

public This add(double x, double y, double z) {
super.add(x, y);
this.z += z;
return (This) this;
}
}

public class Vec4<This> extends Vec3<This> {

etc.

But wait a second, how do we supply a This to Vec3?

    Vec3<Vec3<Vec3<......>>>    ???

We can use a helper class

public class V3 extends Vec3<V3>{}

Now it all works; all add() methods in V3 return V3

    V3 a = new V3();
a.add(10, 20).add(10, 20, 10).add(10, 20).add(10, 20).add(10, 10, 20);

OOP in Java: Class inheritance with method chaining

A method in the parent class that returns this will still return a reference to the object of the child class. You will only be able to treat it as an object of the parent class (unless you cast it) but it will actually be of its original type.

You could consider using generics like this:

// This seems a bit too contrived for my liking. Perhaps someone else will have a better idea.
public class Parent<T extends Parent<T>> {
T foo () {
return (T) this;
}
}

public class Child extends Parent<Child> {
public void bar () {
Child c = foo();
}
}

How to reuse common extended Interface method in Java?

you could solve it with generics:

interface VerifierA extends VerifierC<VerifierA> {
VerifierC<VerifierA> method1();
}

interface VerifierB extends VerifierC<VerifierB> {
VerifierC<VerifierB> method1();
}

interface VerifierC<T> {
T commonMethod();
}

Method chaining + inheritance don’t play well together?

If you want to avoid unchecked cast warnings from your compiler (and don't want to @SuppressWarnings("unchecked")), then you need to do a little more:

First of all, your definition of Pet must be self-referential, because Pet is always a generic type:

abstract class Pet <T extends Pet<T>>

Secondly, the (T) this cast in setName is also unchecked. To avoid this, use the "getThis" technique in the excellent Generics FAQ by Angelika Langer:

The "getThis" trick provides a way to
recover the exact type of the this
reference.

This results in the code below, which compiles and runs without warnings. If you want to extend your subclasses, then the technique still holds (though you'll probably need to genericise your intermediate classes).

The resulting code is:

public class TestClass {

static abstract class Pet <T extends Pet<T>> {
private String name;

protected abstract T getThis();

public T setName(String name) {
this.name = name;
return getThis(); }
}

static class Cat extends Pet<Cat> {
@Override protected Cat getThis() { return this; }

public Cat catchMice() {
System.out.println("I caught a mouse!");
return getThis();
}
}

static class Dog extends Pet<Dog> {
@Override protected Dog getThis() { return this; }

public Dog catchFrisbee() {
System.out.println("I caught a frisbee!");
return getThis();
}
}

public static void main(String[] args) {
Cat c = new Cat();
c.setName("Morris").catchMice();
Dog d = new Dog();
d.setName("Snoopy").catchFrisbee();
}
}


Related Topics



Leave a reply



Submit