Search code examples
javagenericsbigdecimalprimitive

How to implement parameterized arithmetic


I am designing a library that provides a huge collection of classes that perform heavy operations with numbers. I wouldn't like to limit users of the library to a single number type such as int, double, or BigDecimal - and so it would be nice if I could use generics to allow the user to choose their own number type. I am okay with the overhead posed by using primitive wrapper classes as opposed to primitives themselves, as would be necessary in order to use generics, but my problem lies in performing arithmetic.

If I create a hypothetical class MathematicalObject<N extends Number>, then the user can use any type for storing numbers that extends Number - Integer, Double, BigDecimal, et cetera. However the Number class does not provide any interface for arithmetic - I can't add two Numbers without converting them to a double or something alike - which could compromise the accuracy of the number (if a BigDecimal was being used, for example).

So, what is the most performant way I can implement a parameterized use of numbers that allows me to perform arithmetic?


Solution

  • You could use a factory to create a MathematicalObject. the constructor of MathematicalObject could accept a strategy class specifically for performing mathematical operations for that parameterised type, and the factory just chooses the right one based on what the parameterised type is.

    public class MathemeaticalObject<N extends Number> {
        private final NumberOperations<N> ops;
        public MatchematicalObject(NumberOperations<N> ops) {
            this.ops = ops;
        }
    
        public N myComplexOperation(N other) {
            return ops.add(this, other);
        }
    }
    
    public class MathematicalObjectFactory {
        MathematicalObject<Integer> integerObject() {
            return new MathematicalObject(new IntegerOperations());
        }
        ....
    }
    
    public interface NumberOperations<N extends Number> {
        N add(N other);
    }
    
    public class IntegerOperations implements NumberOperations<Integer> {
        @Override
        public Integer add(Integer first, Integer second) {
            return first + second;
        }
    }
    

    The downside would be that you're limited to what values of N are supported. But I think there might not be a way around that. It could also make for some messy code, given that the primitive mathematical operations aren't available directly.