Hello all
I am using Generics in Java to perform some arithmetic operations, but I am getting some error The operator + is undefined for the argument type(s) T, T here is my code

package com.genericsexample;

public class GenericsArithmetic<T> {
    private T number1, number2,sum,product,difference;

    public void AddNumbers(T number1, T number2){
        this.number1 = number1;
        this.number2 = number2;     
    }

    public T getSum(){
//      sum = number1 + number2;
//      when I uncomment the above line I am getting this error message.The operator + is undefined for the argument type(s) T, T
        return sum;
    }

    public void MultNumbers (T number1, T number2){
        this.number1 = number1;
        this.number2 = number2;
//      product = number1 + number2;
    }

    public T getProd (){
        return product;
    }

    public void subtractNumbers (T number1, T number2){
        this.number1 = number1;
        this.number2 = number2;
    }

    public T getDifference(){
        return difference;
    }

}

class DemoGenericsArithmetic {
    public static void main(String[] args) {
        GenericsArithmetic<Integer> integerNumbers = new GenericsArithmetic<>();
        integerNumbers.AddNumbers(100, 100);
        System.out.println("The addition of two numbers is: "+integerNumbers.getSum());
    }
}

what is the problem with that code ?

Thanks
Varun Krishna. P

in your addNumbers do you want to add? - sum = number1 + number2 , your sum is never set

Slavi:
Yes, but I get the error message when I do sum = number1 + number2; Please find the error in the bold face in the post.

Thanks
Varun Krishna. P

You have not restricted the type of your generic argument, so number1 and numnber2 could be any kind of object - Strings, URLs, Files, JRadioButtons... consider

GenericsArithmetic<File> integerNumbers = new GenericsArithmetic<>();

No way you can expect Java to add them.

You need to restrict the type, eg start with something like

public class GenericsArithmetic<T extends Number> {

Edited 2 Years Ago by JamesCherrill

James
Yes I had changed my code to look like this

1.public class GenericsArithmetic<T extends Number> {
2.Then added this to the AddNumbers
sum = number1 + number2;
Even after adding the extends part to the class GenericsArithmetic, I get the same error.

Thanks
Varun Krishna. P

Edited 2 Years Ago by Varunkrishna: Some more explanation

James
I had figured out what went wrong, so I'll fix it and show you the full code.

Thanks
Varun Krishna. P

This really isn't possible given that the Number interface doesn't expose arithmetic methods so even though you can write a GenericArithmetic class which takes only instance of numbers, you can't do implement the operations without casting based on the types passed in.

Sure, but that defeats the purpose of the generic arithmetic class. Let's suppose I create the above GenericsArithmetic class with type parameter as Byte. How would you know which conversion method to use inside the generic add method? My point being, without ugly casts and instanceof checks, it's pretty much impossible to implement a typesafe generic adder without "wrapping" the existing Number type and providing type-safe wrappers.

~s.o.s~ I could not get what you are trying to say, here is my code though it is working it is not the best way to code, so I would like you and James to take a look at it and provide me with some best practices involved in generics.

package com.genericsexample;

public class GenericsArithmetic<T extends Number> {
    private T number1, number2;
    double sum,product,difference;

    public void AddNumbers(T number1, T number2){
        this.number1 = number1;
        this.number2 = number2;

    }

    public double getSum(){
        sum = number1.doubleValue() + number2.doubleValue();
        return sum;
    }

    public void MultNumbers (T number1, T number2){
        this.number1 = number1;
        this.number2 = number2;     
    }

    public double getProd (){
        product = number1.doubleValue() * number2.doubleValue();
        return product;
    }

    public void subtractNumbers (T number1, T number2){
        this.number1 = number1;
        this.number2 = number2;
    }

    public double getDifference(){
        if (number2.doubleValue() > number1.doubleValue()) {
            difference = number2.doubleValue() - number1.doubleValue();
            return difference;      
        }
        else{
            difference = number1.doubleValue() - number2.doubleValue();
            return difference;
        }       

    }

}

class DemoGenericsArithmetic {
    public static void main(String[] args) {
        GenericsArithmetic<Integer> integerNumbers = new GenericsArithmetic<>();

        integerNumbers.AddNumbers(100, 100);
        integerNumbers.subtractNumbers(100, 200);
        integerNumbers.MultNumbers(5, 6);

        System.out.println("The addition of two numbers is: "+integerNumbers.getSum());
        System.out.println("The difference between two numbers is: "+integerNumbers.getDifference());
        System.out.println("The product of two numbers is: "+integerNumbers.getProd());

        GenericsArithmetic<Double> doubleNumber = new GenericsArithmetic<Double>();

        doubleNumber.AddNumbers(150.00, 250.00);
        doubleNumber.subtractNumbers(250.00, 150.00);
        doubleNumber.MultNumbers(10.5, 15.5);

        System.out.println("The sum of two numbers is: "+doubleNumber.getSum());
        System.out.println("The difference between two numbers is: "+doubleNumber.getDifference());
        System.out.println("The product of two numbers is: "+doubleNumber.getProd());

        GenericsArithmetic<Number> floatNumber = new  GenericsArithmetic<>();

        floatNumber.AddNumbers(100.5, 150.235);
        floatNumber.subtractNumbers(99, 199.89);
        floatNumber.MultNumbers(5, 89.5);

        System.out.println("The sum of two numbers is: "+floatNumber.getSum());
        System.out.println("The difference between two numbers is: "+floatNumber.getDifference());
        System.out.println("The product of two numbers is: "+floatNumber.getProd());        
    }
}

Thanks
Varun Krishna. P

That's OK if you are happy to have the answer as a double reardless of whether the generic type for the inputs is Double, Integer, Byte or whatever.
I think ideally you would want to return the same type, ie instead of

public double getSum() {...

you would ideally have

public T getSum() {...

... and that's what ~s.o.s~ is saying is a problem (and I agree with him).

James
As per your suggestion I had changed all the getSum, getDifference, getProd's return value to be T instead of double whith that I had also changed the sum product, difference (line 5) to T instead of double. Now I get the errorType mismatch: cannot convert from double to T in the lines 14,24,35 and 39.

Thanks
Varun Krishna. P

Edited 2 Years Ago by Varunkrishna: Indentation

I was NOT suggesting you did that - I was agreeing with ~s.o.s~ that it would be a difficult/messy thing to do. It would need a lot more code than just changing the method header.

James, so how do I do that ?

It would need a lot more code than just changing the method header.

You would have to check the runtime type of the parameters then use a nested if to convert to the appropriate type to do the arithmetic. Eg If the type is Double, convert to double, if it's Integer, convert to int etc etc. That makes a mess of the using generics in the first place. As far as I know there's no "good" way to do this.

I'm not sure about the purpose of this exercise but if it is learning more about generics, it would be much better to implement your own wrapper types instead of fighting with the type system. As a simple example:

public class GenericTest {

    public static void main(String[] args) {
        GenericArithmetic<RichInt> gai = new GenericArithmetic<>();
        RichInt addRes = gai.add(RichInt.of(100), RichInt.of(400));
        System.out.printf("Result of adding integers => %s%n", addRes);

        GenericArithmetic<RichDouble> gad = new GenericArithmetic<>();
        RichDouble subRes = gad.subtract(RichDouble.of(100.8), RichDouble.of(50.3));
        System.out.printf("Result of subtracting doubles => %s%n", subRes);
    }

}

interface Numeric<T> {
    T plus(T other);

    T minus(T other);
}

class GenericArithmetic<T extends Numeric<T>> {
    public T add(T first, T second) {
        return first.plus(second);
    }

    public T subtract(T first, T second) {
        return first.minus(second);
    }
}

class RichInt implements Numeric<RichInt> {
    private int i;

    private RichInt(int i) {
        this.i = i;
    }

    public static RichInt of(int i) {
        return new RichInt(i);
    }

    @Override
    public RichInt plus(RichInt other) {
        return RichInt.of(this.i + other.i);
    }

    @Override
    public RichInt minus(RichInt other) {
        return RichInt.of(this.i - other.i);
    }

    @Override
    public String toString() {
        return String.format("%s(%s)", "RichInt", i);
    }
}

class RichDouble implements Numeric<RichDouble> {
    private double d;

    private RichDouble(double d) {
        this.d = d;
    }

    public static RichDouble of(double d) {
        return new RichDouble(d);
    }

    @Override
    public RichDouble plus(RichDouble other) {
        return RichDouble.of(this.d + other.d);
    }

    @Override
    public RichDouble minus(RichDouble other) {
        return RichDouble.of(this.d - other.d);
    }

    @Override
    public String toString() {
        return String.format("%s(%s)", "RichDouble", d);
    }
}
This article has been dead for over six months. Start a new discussion instead.