Computer Algebra System implementation I have got it working in a way so that there is one superclass, MathObject. In this implementation there is only a Constant subclass. I was forced to implement an abstract MathObject add(MathObject that) and an abstract MathObject add(Constant that) for reasons.

I would like to get that abstract MathObject add(Constant) out of MathObject because its already in Constant and I would have to update MathObject for each object I add.

I'd like to focus on maintainability and expandability first before adding too much features (this is my third or so attempt).

public class MathMain{
    public static void main(String[] args){
        Constant constant = new Constant(1);
        constant.add(constant);
        MathObject mathObject = (MathObject)constant;
        constant.add(mathObject);
        constant.add((Constant)mathObject);
        mathObject.add(constant);
    }
}




public abstract class MathObject{
    public abstract MathObject add(MathObject that);

    public abstract MathObject add(Constant that);

    public abstract MathObject substract(MathObject that);

    public abstract MathObject substract(MathObject that);

    public abstract double evaluate();
}




public class Constant extends MathObject{
    public final double c;

    public Constant(double c){
        this.c = c;
    }

    public MathObject add(MathObject that){
        return that.add(this);
    }

    public MathObject substract(MathObject that){
        return that.substract(this);
    }

    public Constant add(Constant addend){
        return new Constant(c + addend.c);
    }

    public Constant substract(Constant subtrahend){
        return new Constant(c - subtrahend.c);
    }

    public double evaluate(){
        return c;
    }
}
You have a compile error since MathObject has 2 identical substract methods; I assume this is a copy-paste error and the second should have Constant instead of MathObject as its parameter.



substract -> subtract.



MathObject only has abstract methods. If it is not going to give any common implementation, I would recommend making it an interface instead of an abstract class, as that would allow implementations to extend a different class as well.

Additionally, I would change evaluate() to doubleValue(), similar to the identically named method in the Number class. What if you want to have a CAS system that computes using BigDecimal, but you want to reuse your code?



Constant has a public final double c. That should be private; you (almost) never want to have a public field for a class.



The Big Problem

There is currently a rather big problem with your design: MathObject treats Constants differently from MathObjects. This should not be the case. Rather, the Constant class should comply with the MathObject interface:

public class Constant implements MathObject {
    private final double c;

    public Constant(double c) {
        this.c = c;
    }

    // Always add this when you override a method. It doesn't enforce anything
    // in Java's compile (unfortunately), but you will get a warning if you have
    // a method with @Override that doesn't actually override anything. However,
    // what this annotation does do is that it documents. If I come in and look at your
    // code, it is immediately clear to me that these methods are overriding
    // some parent method. Otherwise, I might look at this and think, "What is
    // this for?" For other examples, it can be clearer why @Override is useful,
    // but get in to the habit of always adding @Override
    @Override
    public MathObject add(MathObject that) {
        // This is an example of something you could do
        if (that instanceof Constant) {
            return new Constant(c + ((Constant) that).c);
        }
        return that.add(this);
    }

    @Override
    public MathObject subtract(MathObject that) {
        // return that.subtract(this);
        // Some implementation here
    }

    @Override
    public double doubleValue() {
        return c;
    }
}


So then MathObject would be:

public interface MathObject {
    MathObject add(MathObject that);

    MathObject subtract(MathObject that);

    double doubleValue();
}