4

So I have a couple of inherited classes defined like so.

class Base {
    public Base chainedMethodA() {
        // some stuff
        return this;
    }
}

class Derived extends Base {
    public Derived chainedMethodB() {
        // some stuff
        return this;
    }
}

Now, the following code works:

Derived obj = new Derived();
obj.chainedMethodB().chainedMethodA();

But this does not (notice the switched order of function calls):

Derived obj = new Derived();
obj.chainedMethodA().chainedMethodB();

The compiler gives an error on the chainedMethodB() function call. I can understand that this is because when you run chainedMethodA(), it returns an object of type Base, which does not have chainedMethodB defined.

I can think of a few solutions to this problem:

  1. Chain methods while paying attention to order (call Derived's methods first, and then call Base's methods). This looks like a very brittle solution.
  2. Override chainedMethodA in Derived so it returns an instance of Derived instead of Base. This looks like a waste of inheritance.

Is there any elegant way around this problem? Maybe some construct that magically changes chainedMethodA to return a Derived instance when called by an object of type Derived, without being explicitly overridden in Derived.

3
  • 5
    2 isn't a waste of inheritance. It is what inheritance is: override to do something more specific, in this case: return a more specific type. Commented May 4, 2016 at 21:43
  • 1
    @TI Sure it will: you can override and declare to return a more specific type. With @Override public Derived chainedMethodA() { ... } Commented May 4, 2016 at 22:08
  • Keep in mind that if you want Derived's chainedMethodA to return an instance of Derived then it can't call the super implementation anyway (because that might return an actual Base which isn't a Derived). So you're not losing anything that way, and you allow Derived objects to still be used as Bases. Commented May 4, 2016 at 22:17

2 Answers 2

2

Override chainedMethodA in Derived so it returns an instance of Derived instead of Base. This looks like a waste of inheritance.

You're wrong. You aren't wasting inheritance.

Technique of overriding is to do just that namely specialize a method. Override can be done when the returned type is the same or a subtype of the return type declared in the original overridden method in the superclass. So in this case you are violating nothing.

Read here for more about overriding.

Here example 1: (calling the superclass method)

public class Derived extends Base {
    @Override
    public Derived chainedMethodA(){

         super.chainedMethodA();
         //some stuff
        return this;
    }

    public Derived chainedMethodB() {
        // some stuff
        return this;
    }
}

Here example 2: (changing it completele)

public class Derived extends Base {
    @Override
    public Derived chainedMethodA(){
        //some stuff
        return this;
    }

    public Derived chainedMethodB() {
        // some stuff
        return this;
    }
    }
Sign up to request clarification or add additional context in comments.

5 Comments

IMO, your answer could use of an example of such overriding :).
Thanks for editing! I'm not so sure about return (Derived) super.chainedMethodA();. chainedMethodA could return a Base and this would fail (ClassCastException). How about super.chainedMethodA(); return this;?
@Tunaki yeah mixed solitution obviusly working. But when could return a Base? If the chainMethodA is called by Derived class.. this is an instance of Derived. Isn't?
Imagine chainedMethodA() returns for some reason new Base() :). (it would defeat the name I agree but it isn't strictly forbidden).
Ahahahah yeah i was refering to this example. However i'll edit to be more generic
0

In this situation inheritance is probably the simplest solution.

However, your last sentence pretty much explains generics:

Maybe some construct that magically changes chainedMethodA to return a Derived instance when called by an object of type Derived, without being explicitly overridden in Derived.

So something like this may be useful in other similar use cases:

static class Base {
    public <T extends Base> T chainedMethodA(Class<T> clazz) throws Exception {
        // some stuff
        return clazz.cast(this);
    }
}

static class Derived extends Base {
    public Derived chainedMethodB() {
        // some stuff
        return this;
    }
}

public static void main(String args[]) throws Exception {
    Derived obj = new Derived();
    obj.chainedMethodA(Derived.class).chainedMethodB();
}

2 Comments

No. This is overkill. Do you really think introducing the Reflection API is aboslutely necessary here? Plus, it does not do what the OP wants since it creates a new instance.
OP was more worried about return types so I didn't pay attention to what the method was actually doing. Nevertheless, Ive updated so it returns the same instance. (and I agree its probably overkill in the op situation, hence the first line)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.