1

I have a parent class, Parent, with two child classes, A and B. I have an interface, Function<Type1 extends Parent,Type2 extends Parent>, that allows the programmer to write a specific function, Type2 of(Type1 t), that takes a Type1 to a Type2. The interface is wrapped in a class, Wrapper<Type1 extends Parent,Type2 extends Parent> that contains helpful information, such as Class<Type1> type1Class, etc.

My problem arises when I try to implement an add method for the Wrapper class, Wrapper<Type1,Type2> add(Wrapper<Type1,Type2> additionalWrapper). I'm trying to add the two Functions together, but I'm having difficulty getting a Type2 to output instead of a Parent due to the erasure.

How can I make the add method output a Type2 instead of a Parent?

public class Parent {
    protected int value;
    public void setValue(int x){ value = x; }
    public int getValue(){ return value; }
    public Parent(){}
    public Parent(int x){setValue(x);}
    public Parent add(Parent p){return null;}
}


public class A extends Parent{
    public A(){ setValue(1); }
    public A(int x){ setValue(x); }
    public A(B b){ setValue( b.getValue()); }
    public A add(A a){ return new A( getValue()+a.getValue()); }
    public A add(B b){ return new A( getValue()*b.getValue()); }
}

public class B extends Parent{
    public B(){ setValue(2); }
    public B(int x){ setValue(x); }
    public B(A a){ setValue(a.getValue()); }
    public B add(B b){ return new B(getValue() + b.getValue()); }
    public B add(A a){ return new B(getValue() * a.getValue()); }
}

public interface Function <Type1 extends Parent, Type2 extends Parent> {
    public Type2 of(Type1 t);
}

public class Wrapper<Type1 extends Parent, Type2 extends Parent> {

    protected Function<Type1,Type2> function;
    protected Class<Type1> type1Class;
    protected Class<Type2> type2Class;
    public Wrapper(final Class<Type1> t1, final Class<Type2> t2, Function<Type1,Type2> x) {
        type1Class = t1;
        type2Class = t2;
        function = x;
    }

    public Type2 of(Type1 t){
        return function.of(t);
    }
    public Wrapper<Type1,Type2> add(final Wrapper<Type1,Type2> additionalWrapper){
        return new Wrapper<Type1,Type2>( type1Class, type2Class, new Function<Type1,Type2>(){
            public Type2 of(Type1 t){
                try{
                    Type2 term = function.of(t);
                    Type2 summand = additionalWrapper.of(t);
                    Type2 sum = (Type2) term.add(summand); ///Problem happens here. term and summand are both interpreted as Parent by the erasure, I think, and therefore add outputs null, setting sum=null.
                    return sum;
                } catch(Exception e){
                    e.printStackTrace();
                    return null;
                }
            }
        });
    }
}

public class Main {
    public static void main(String[] args){
        Wrapper<A, B> wrapper1 = new Wrapper<A, B>(A.class,B.class,new Function<A, B>() {
            @Override
            public B of(A a) {
                return new B(a);
            }
        });
        Wrapper<A, B> wrapper2 = new Wrapper<A, B>(A.class,B.class,new Function<A, B>() {
            @Override
            public B of(A a) {
                B b = new B();
                return b.add(a);
            }
        });
        Wrapper<A,B> wrapper3 = wrapper1.add(wrapper2);

        A a = new A(3);
        B b = wrapper3.of(a);

        System.out.println(b.getValue()); ///Error happens here because b was set to null and therefore doesn't contain int value.

    }
}
user2303321
  • 187
  • 1
  • 10
  • Try adding the `@Override` annotation to see why you're always getting `null` (hint: you aren't overriding `add`). – Elliott Frisch Oct 06 '18 at 04:22
  • @ElliottFrisch I added @Override to the add methods in A and B, but the problem is that when I put the corresponding functions in the Parent class, they conflicted because in class B I have `B add(B b)` but in class A I have `A add(B b)`. Is there a way around this? – user2303321 Oct 06 '18 at 04:30
  • It looks like your Parent class should have two methods, `Parent add(A a)` and `Parent add(B b)`. – Louis Wasserman Oct 06 '18 at 04:34
  • @LouisWasserman Ok. I did what you said and that corrected the definition conflict, but the `add` method in the `Wrapper` class still calls the `add` method from the `Parent` class when `b.add(a)` is called, which makes the output null. – user2303321 Oct 06 '18 at 04:39
  • Then you're pretty out of luck. You need to do an actual instanceof check; overloading alone won't do it. – Louis Wasserman Oct 06 '18 at 04:40
  • But why do you need two methods? they have same logic.. isn't it? Do you want to `overload` or `override`? – Anand Vaidya Oct 06 '18 at 04:41
  • @AnandVaidya This is a simplified version of the actual code, in which A and B have different structures. A is a scalar and B is a vector. Adding a scalar to a scalar is different from adding a scalar to a vector, so I need to have separate methods for each child class. – user2303321 Oct 06 '18 at 04:50

2 Answers2

1

As Louis Wasserman suggested in a comment, I needed to use instanceof within a single overridden function Parent add(Parent p).

In classes A and B, I needed to have this function:

@Override
public Parent add(Parent p){
    if (p instanceof A){
        A a = (A) p;
        return add(a);
    }
    else if (p instanceof B){
        B b = (B) p;
        return add(b);
    }
    else return null;
}
user2303321
  • 187
  • 1
  • 10
  • Yes, I was about to post the same. Although I would like to mention that this is against SOLID principles, and I would recommend to revisit your design. – Anand Vaidya Oct 06 '18 at 05:13
  • @AnandVaidya Could you please explain how it's against SOLID principles? I would like to implement a proper design. – user2303321 Oct 06 '18 at 05:20
  • https://stackoverflow.com/questions/20589590/why-not-use-instanceof-operator-in-oop-design – Anand Vaidya Oct 06 '18 at 05:27
  • @AnandVaidya I see. Is there a better way I could do this? – user2303321 Oct 06 '18 at 05:41
  • @AnandVaidya Here is a link to a more representative version of the code, but still not the full code, as that would be too big to post. https://stackoverflow.com/questions/52684258/how-to-determine-type-of-child-class-from-method-of-parent-class-without-instanc – user2303321 Oct 06 '18 at 23:52
0

Basically you do not two methods to add A and B, Its against the polymorphysm or SOLID principles. You can frame your classes like below -

class A extends Parent{
public A(){ setValue(1); }
public A(int x){ setValue(x); }
public A(B b){ setValue( b.getValue()); }
@Override
public A add(Parent a){ return new A( getValue()+a.getValue()); }
}

class B extends Parent{
public B(){ setValue(2); }
public B(int x){ setValue(x); }
public B(A a){ setValue(a.getValue()); }
@Override
public B add(Parent b){ return new B(getValue() + b.getValue()); }
}

Because add is defined in Parent, only one implementation is sufficient. In Current scenario, because the signatures of add in Class A doesn't match with signature in Parent, and thus the method is not overridden at all

You will come to know if you add @Override on your add methods. Compiler will throw errors.

Hope this helps.

Anand Vaidya
  • 1,099
  • 8
  • 23
  • I see. This is only a simplified version of my actual problem, where A and B have very different structures. A is a scalar and B is a vector. Both descend from a `Space` class. Adding a scalar to a scalar requires different code than adding a scalar to a vector, so I need to have separate methods for each child class. Is this possible? – user2303321 Oct 06 '18 at 04:49
  • Is it possible to post actual declarations class A and B? Its difficult to imagine what you are trying to do – Anand Vaidya Oct 06 '18 at 05:03
  • No need. I figured it out based on Luis Wasserman's comment. Thanks for your help, Anand. – user2303321 Oct 06 '18 at 05:04