Sunday, January 27, 2008

Numbers in an Object-Oriented World, Part II

Yes, I have a blog again. I need a place to rant as I design PX. Not spending money on getting my domain name back though when I don't know if this will last.

Over a year ago (on my old site), I wrote a post on representing numbers in an object oriented language. It talked about how most languages ignore the fact that every integer is a rational. Every rational is a real. Every real is complex. And all these are numbers. You could invent a hierarchy it would have to consist of interface or data-less abstract classes because an integer requires far less data than a complex number and having to inherit the complex number's two floating point fields (or whatever they are) isn't what people want to hear.

At least Java made a Number base class. A tiny step in the right direction. C# ignores number hierarchies completely (and don't even get me started on what a copout boxing and unboxing is). But Java misses out on so much more that can be put in there. Java has five integer-data classes: Byte, Short, Integer, Long, and BigInteger. What if I just wanted to know that my Number object was an integer and didn't care which precision it has? Do they share a common Integer interface? Of course not.

Operator overloading exists only to justify mathematical operators in an OO language. But really I only like operator overloading for numeric types. C++'s operator abuse is the prime reason. Operator overloading also presents a fun challenge for number classes. The seemingly simplistic type promotion for operations that we take for granted (such as converting a int to a float because adding it to another float) makes truly representing the difficult when a number's true type isn't known until run time. Also you need to account for everything. For example:

   Number x = someFunc();
Number y = x + 32.0;

If "x" is an Integer, the typical rules say it gets promoted to Float, and then added. Should the Integer operator's know this? Cause is so, Float's operator must know to promote Integers too when if the expression were reversed to "32.0 + x". Should Integer delegate to Float's operators and trust they will know what to do with Integers? Suppose x is an object from some custom number class, the Float needs to know to delegate the operation to the custom number class. And in turn, if the customer number class doesn't know how to add to floats, it may delegate back to Float and it repeats in never ending cycle. So many dilemmas from so simple of a mathematical problem.

Another unfortunate side effect of numbers in OOP is "static classes" (meaning classes with all static data and methods, no constructors, and can't be inherited). It's like the language designers thought they were done and then wondered "what the hell do we do with the math functions like pow and sin?" Good OO practice would say throw them in a normal class that can be instantiated and have a Math interface or something for usability. But the Math object wouldn't need a state so nobody wanted to make a stateless Math class that you needed to make a Math object before using a math function. So they threw them in a "static class" which serves no purpose other than being a namespace. I mean come on. A Java book I own defines a class as "a group of objects that share common state and behavior. A class is an abstraction or description of an object." Well, the Math class can have no objects. It fails this definition on so many levels. Is really that important that every method be in a class? Couldn't they settle for modules?

So why am I ranting? Why is this important to me? Because in my PX design decisions, this is what I'm thinking about. How can I make a (statically-typed) language flexible enough to support true object oriented numbers.

In the future, I'll probably be showing off various PX ideas like replacing the typical Java/C# "class" and "interface" with a more flexible model.


No comments: