Reputation: 31
I need help with a problem I have with generics in Java. I'm writing this Computer algebra system, where the user enters a math expression and the system works with it in different ways (expand it, simplify it etc). It worked fine for expressions containing natural numbers, and I wanted to expand it to work with mathematical sets as well. Instead of +, you would have the intersection operator, etc.
At first, I started recording everything for the sets, but then I realized this was probably not good and started using generics.
Instead of having one parse tree like MathExpr
and one like SetExpr
, I thought I could just have a generic Expression<T>
and build a base class Number
and a base class Set
.
To try to clarify, I want a mathematical expression like (2 * a) + (3 + 2) to be an instance of a class Expression<Number>
and a set expression like (A ∪ B) ∩ C to be an instance of Expression<Set>
. I can then perform different operations on this, like calculate the depth etc.
The + operation is implemented as one class, the * as one class etc. Both these classes are subclasses of an abstract class called TwoExpr
which in turn is a subclass of the abstract class Expr
. This is how I have done it now and everything works fine.
When I wanted to change my code I made my Expr
class generic. That is Expr<T>
. I also changed TwoExpr to TwoExpr<T>
and created a base class Number
.
The problem is, now I can't seem to instantiate objects of the type Sum<Number>
.
I get a "Type mismatch: cannot convert from Sum to Expr<Number>
" error. But Sum
is a subclass of TwoExpr<Number>
, which in turn is a subclass of Expr<Number>
. As you may realize, I can't make the class Sum
generic and call it Sum<Number>
, because all arithmetic operations don't have analogues for sets.
I have always been able to create objects like
Expr zero= new Leaf(0);
Variable a = new Variable("a");
Expr aPlusZero = new Sum(a, zero);
When I changed to generics, the same code looks like this:
Expr<Number> zero= new Leaf<Number>(new Number(0)); //works fine
Variable<Number> a = new Variable<Number>("a"); //works fine
Expr<Number> APlusZero=new Sum(a,zero); //gives a "Type mismatch:
//cannot convert from Sum to Expr<Number>" error
How come it doesn't recognize that Sum(a,zero)
is a subclass of Expr<Number>
, when it says in the declaration of Sum
public class Sum extends TwoExpr<Number> {
public Sum(Expr<Number> a, Expr<Number> b) {
super(a, b);
}
...
}
and in the declaration of TwoExpr
public abstract class TwoExpr<T> extends Expr<T> {
protected Expr<T> a;
protected Expr<T> b;
public TwoExpr(Expr<T> a, Expr<T> b) {
this.a=a;
this.b=b;
}
...
}
I know that Lizkows substitution principle doesn’t apply for generic arguments. But Number isn’t a subclass of anything (except Object) and don't have any subclasses. I hope I've been fairly clear about what I'm trying to do and what problem I have. Does anybody have any idea how to solve it? Please tell me if anything was unclear in the above or if you want more code.
Thanks in advance.
Mattias
Upvotes: 3
Views: 2231
Reputation: 18743
Sum
does not import Types.Number
. So it's not Expr<Types.Number>
but Expr<java.lang.Number>
. I would assume this would give a compilation error not only on the assignment but also on the construction of new Sum(vA, zero)
, but maybe the compiler sees the other error first.
Upvotes: 0
Reputation: 3056
Maybe try to debug it:
Object = new Sum(a,zero);
System.out.println(o.getClass().getGenericSuperclass());
Furthermore maybe is a better solution for your system.
Upvotes: 0
Reputation: 4829
I think your problem is in the classes you did not show, I tried the following and it works:
Expr<Number> zero= new Expr<Number>();
Expr<Number> a= new Expr<Number>();
Expr<Number> APlusZero=new Sum(a,zero);
Might it be that Variable is not an Expr?
UPDATE:
I played a little creating Variable and Leaf as I imagine them and it all works:
public class Number {
public Number(int i){}
}
public class Variable<T> extends Expr<T> {
public Variable(String s){}
}
public class Leaf<T> extends Expr<T> {
public Leaf(T t) {
super();
}
}
public class Expr<T> {
}
public class TwoExpr<T> extends Expr<T> {
public TwoExpr(Expr<T> a, Expr<T> b) {
}
}
public class Sum extends TwoExpr<Number> {
public Sum(Expr<Number> a, Expr<Number> b) {
super(a, b);
}
}
public class AllTogether {
public static void main(String[] args) {
Expr<Number> zero= new Leaf<Number>(new Number(0));
Variable<Number> a = new Variable<Number>("a");
Expr<Number> APlusZero=new Sum(a,zero);
}
}
If you take the extends Expr from Variable it does give the error you experience, might it be this the cause?
Upvotes: 2