0

Does anybody know why Im getting this error?

error: cannot find symbol return left.evaluate() + right.evaluate(); symbol: method evaluate() location: variable left of type T where T is a type-variable: T extends Object declared in class Operation

package expevaluator;

interface Expression<T> {

    T evaluate();
}

class Constant<T> implements Expression {

    private final T value;

    public Constant(T value) {
        this.value = value;
    }

    @Override
    public T evaluate() {
        return value;
    }

}

abstract class Operation<T> implements Expression {

    public T left;
    public T right;
}

class Addition<T> extends Operation {

    public Addition(T left, T right) {
        super.left = left;
        super.right = right;
    }

    @Override
    public T evaluate() {
        if(left instanceof Integer){
            if(right instanceof Integer){
                return super.left.evaluate() + right.evaluate();
            }else{
                return left.evaluate() + right.evaluate(); 
            }
        }else{
            return left.evaluate() + right.evaluate();
        }
    }
}

EDIT:

package expevaluator;

import java.util.logging.Level;
import java.util.logging.Logger;

interface Expression<T extends Number> {

    T evaluate();
}

class Constant<T extends Number> implements Expression{

    private final T value;

    public Constant(T value) {
        this.value = value;
    }

    @Override
    public T evaluate() {
        return this.value;
    }

}

abstract class Operation<T> implements Expression {
    public T left;
    public T right;
}

class Addition extends Operation {

    public Addition(Constant left, Constant right) {
        super.left =  left.evaluate();
        super.right = right.evaluate();
    }

    @Override
    public Number evaluate() {
        String name = "expevaluator." + super.left.getClass().getSimpleName() + super.right.getClass().getSimpleName() + "Addition";
        try {
            Object instance;
            instance = Class.forName(name).newInstance();
            return (Number) instance;
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException ex) {
            Logger.getLogger(Addition.class.getName()).log(Level.SEVERE, null, ex);
        }
        /*if (super.left instanceof Integer && super.right instanceof Integer) return new IntIntAddition().evaluate((Integer)super.left,(Integer)super.right);
        if (super.left instanceof Integer && super.right instanceof Double) return new IntDoubleAddition().evaluate((Integer)super.left,(Double)super.right);
        if (super.left instanceof Double && super.right instanceof Integer) return new DoubleIntAddition().evaluate((Double)super.left,(Integer)super.right);
        if (super.left instanceof Double && super.right instanceof Double) return new DoubleDoubleAddition().evaluate((Double)super.left,(Double)super.right);*/
        return null;

    }

}

class IntegerIntegerAddition{

    IntegerIntegerAddition() {

    }

    public Number evaluate(int left, int right) {
        return left + right;
    }

}

class IntegerDoubleAddition {

    public IntegerDoubleAddition() {
    }

    public Number evaluate(int left, double right) {
        return left + right;
    }
}
class DoubleIntegerAddition {

    public DoubleIntegerAddition() {
    }

    public Number evaluate(double left, int right) {
        return left + right;
    }
}
class DoubleDoubleAddition {

    public DoubleDoubleAddition() {
    }

    public Number evaluate(double left, double right) {
        return left + right;
    }
}

I've been succes with it, now I want to use reflection in the addition class.

I want to instanciate a class and then call the evaluate() method.

Subiendo
  • 47
  • 7

3 Answers3

1

T is never bound, so its upper bound is Object. Therefore, only methods on Object are available.

You are mixing up the value type of the expression (T, which could be Integer) and the sub expressions themselves (subtypes of Expression). Perhaps it should look like this:

public Addition(Expression<T> left, Expression<T> right) {
   //...

Note also that Constant<T> and similar should implement Expression<T>, not the raw type Expression. Similarly, Addition<T> should extend Operation<T>, not Operation.

That said, your approach to Addition is broken in general, because it can't extend to the general case (you can't just apply the + operator to any arbitrary type). I would implement Addition solely for the Integer case:

class IntegerAddition extends Operation<Integer> {

    private final Expression<Integer> left, right;

    public IntegerAddition(Expression<Integer> left, Expression<Integer> right) {
        this.left = left;
        this.right = right;
    }

    public Integer evaluate() {
        return left.evaluate() + right.evaluate();
    }
}
Mark Peters
  • 80,126
  • 17
  • 159
  • 190
  • Do you know how to add reflection to my evaluate method because I want to run the evaluate method in runtime? – Subiendo Apr 02 '14 at 10:43
0

You need to cast the super.left to Expression, or any other type that contains an evaluate() function at compile-time. Remember, java has type erasure and is a strongly typed language, your Addition.Evaluate() method has no idea what type left and right will be at compile-time, and since evaluate() is not defined in Operation, there is a compiler error.

public T evaluate() {
    if(left instanceof Integer){
        if(right instanceof Integer){
            return ((Expression)super.left).evaluate() + ((Expression)right).evaluate();
        }else{
            return ((Expression)left).evaluate() + ((Expression)right).evaluate(); 
        }
    }else{
        return ((Expression)left).evaluate() + ((Expression)right).evaluate();
    }
}

Additionally, you cannot add the objects returned by the evaluate() method as generics in java are really just typed as Java.Lang.Object. Instead, you will need to have a type-aware add() method that does the adding for you using the instanceOf operator, as there is no way to override the "+" operator in java. (This seems like what you are trying to achieve, you just have not gone the full 100 yards yet)

Just think of generic type "variables" as meaningless in java, they just help you to avoid type errors at compile-time, but are compiled down to their raw types in byte code.

Edit:

Also... I'm not exactly sure what about block :

if(left instanceof Integer){
        if(right instanceof Integer){

You then go on to call left.evaluate() and try to add it to right.evaluate()... but the problem here is that you don't seem to have anything that derives from Integer so all you are left with strangely behaving code. If you DO know that you will be dealing with integers, and that all of your nested left and right objects will also be Integers, you should just cast the expressions to int and then add them together. Better yet, you should qualify your types with Integer so that you are working with the non-generic type qualified Addition class.

TTT
  • 1,952
  • 18
  • 33
0

You've got at least two problems.

  • left and right are type T, but you're trying to call evaluate() on them, which is defined in class Constant<T>. Because left and right aren't necessarily of type Constant<?>, the compiler can't make sense of these calls.
  • You're trying to add two expressions, of type T. This doesn't make sense for most types that T could be. For example, what do you expect a + b to give you if a and b are both of type Color or InputStream or something else that it doesn't make sense to add?
Dawood ibn Kareem
  • 77,785
  • 15
  • 98
  • 110