Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

From a specific expression tree to a generic one - java

Tags:

java

generics

I want to write an abstract class 'Expression' that takes either Integer or Boolean expressions and evaluates them through subclasses like 'Add', 'Divide' for Integer and 'And', 'Or' for Boolean expressions. In the end it comes down to writing subclasses that implement their own evaluate() method. I found an implementation in a book but it only works with double values. Here it is:

abstract class Expr {
    abstract double eval();
}
abstract class BinOp extends Expr {
    Expr left;
    Expr right;
    BinOp(Expr l, Expr r) {
    }
}
class Const extends Expr {
    private double value;
    Const( double val ) {
        this.value = val;
    }
    double eval () {
        return this.value;
    }//eval
}

Now, for the class BinOp I can write a class 'Add' that extends it, calls it's constructor and implements eval() with the multiplication of 2 Const objects, which eval() themselves and simply return the value they were instantiated with.

How would this work if I wanted to do it with Expr that are not strictly bound to evaluate to double, but to either int or boolean? I've read up on generics but I can't seem to correctly design the classes like Expr such that my code compiles. Here's my try:

public abstract class Expression<T> {
    abstract T evaluate();
}
public class Const<T> extends Expression{
    private T n;
    public Const(T x) { n = x; }
    public Const<Integer> integerConst(Integer n) {
        return new Const<>(n);
    }
    public Const<Boolean> booleanConstConst(Boolean n) {
        return new Const<>(n);
    }
    public T evaluate() {
        return n;
    }
}

Now I don't want anybody to do my homework for me, so I'm just asking where the fault in my approach lies and if someone could point me in the right direction. Thank you.

like image 232
Bel Riose Avatar asked Nov 06 '22 23:11

Bel Riose


1 Answers

Here are some suggestions:

  • First of all, you shouldn't use raw types, so Const<T> should extend Expression<T>.

  • Now, your integerConst and booleanConstConst methods look like factory methods, so they should be static.

  • That said, I'm not sure it's a good idea to have these factory methods in the Const class, since it would force you to change the Const type if you wanted to support a 3rd expression type (in addition to Boolean and Integer). Instead you might want to consider sub-classing Const:

    public class IntegerConst extends Const<Integer> {
        public IntegerConst(Integer n) {
            super(n);
        }
    }
    
    public class BooleanConst extends Const<Boolean> {
        public BooleanConst(Boolean b) {
            super(b);
        }
    }
    

Hopefully you can continue from here.

like image 149
Eran Avatar answered Nov 13 '22 21:11

Eran