tags:

views:

196

answers:

4

My question is eerily similar to "Writing a generic class to handle built-in types" including being inspired by the fact of working on a class to handle operations on matrices. Although that question was asked using C# and pointed to an article on Generic Operators.

I don't get it. Java Number does not have an add method so you can have a method like:

public Number myAdd(Number a, Number b){
     return a.add(b);
}

So how do you handle a case where you want to be able to handle multiple types of Numbers in Java?

A: 

Personally, I use BigDecimals for almost everything (but that is mainly because I work with currency values). They handle all numeric values of any size. Because of that, in my opinion they are a generic value and could be used as such in your hypothetical example instead of the Number abstract class. Everything can be turned into a BigDecimal, why not use it?

public BigDecimal myAdd(BigDecimal a, BigDecimal b) {
    return a.add(b);
}

EDIT: To address BigBrothers comment below, you could always use the doubleValue() method to create your own generic method. The only problem with this is that you may lose precision in some rare cases where someone IS passing in a BigDecimal and it is larger than a Double.maxValue

public Number myAdd(Number a, Number b) {
    return new BigDecimal(a.doubleValue() + b.doubleValue());
}

A BigDecimal is a Number, so returning one is of no consequence.

Nemi
While I see what you are saying, I was hoping for something more elegant I guess.
jschoen
+1  A: 

I don't get it. Java Number does not have an add method ...

Suppose that java.lang.Number did have an add method or methods, how would you define its signature? How would you define its semantics? How would you deal with "mixed mode" arithmetic?

While it is no doubt possible to answer these questions and design an API, the result is likely to be tricky to use correctly. In addition, it is most unusual for an application to need to perform "representation agnostic" arithmetic. Usually you want / need explicit control over the way that arithmetic is performed and conversions happen. (The Java primitive type promotion rules are already difficult enough for people to get their heads around!!)

All in all, I think that Sun have done us a service by not trying to support arithmetic in the Number API.

Stephen C
+2  A: 

The fundamental problem is with the Java type system which is very primitive.

Since there is no notion of a sealed set of types in Java (nor is it possible for Java to infer the types like Haskell does) there is no way to make make a general Number + Number -> Number without trickery.

For primitives (and those objects like Integer which can be automagically mapped to them) types promotion and the + operation is part of the language. (And this is actual part of the problem: what should Number a + Number b return where a and b are of different types?)

If you really want this behavior you'll have to find (or create) your own custom class that either uses reflection or a series (of checks and) casts and such. Even if you use generics (remember that generics are type-erased) casting will need to be done.

I imagine these problems are part of the reason why Number is as bland as it is.

pst
"what should Number a + Number b return where a and b are of different types" is pretty much _all_ of the problem. :)
David Moles
+1  A: 

How good do you want the result to be? If the answer is "good enough, mostly", then this should be sufficent:

public Number myAdd(Number a, Number b){
     return a.doubleValue() + b.doubleValue();
}

But if you want something that, say, matches the promotion semantics of Java primitives, you're probably going to have to write it yourself. And then you'll have to figure out what the rules are for all combinations of "non-standard" Number implementations, including BigDecimal, BigInteger, AtomicDouble, AtomicLong, everything in org.apache.commons.lang.mutable, and any random implementation that somebody might decide to write next Tuesday.

It's not clear what the right thing to do is in most of these cases -- converting everything to BigDecimal, for instance, is not an option if one of the arguments is Apache Commons' Fraction.ONE_THIRD; and besides, doing the conversion in a general way presents the same problems as doing the addition in a general way. But having an add() method on Number would require every Number implementation to handle all these cases -- and that's probably why it isn't there.

David Moles