People are the Problem, not Operator Overloading
Posted on March 1, 2008
Filed Under Programming, Programming Languages |
Alternate Title
I’m 12 years late to the party. Again. Hear me out.
Java Does it Wrong
Java’s design leans heavily on the (correct) belief that the average programmer is imperfect, lazy, and ill-informed. In response, Java acts like a typical overbearing parent. Java knows that you’re too lazy to check whether or not you’re REALLY writing inside of array bounds, so Java does it for you. Programmers are too forgetful to free all memory that they have initialized. Java does it for you. In fact, pointers are hard, so you don’t get to use them in the traditional sense. At all. Maybe when you’re older.
Some very good things came from this policy, like memory management, batteries-included mentality, and Javadoc. Javadoc is a tool that automatically generates pleasant documentation based on your comments, and it’s a freebie. You’re left with no excuse but to actually document your program, unless you refuse out of malice.
However, operator overloading must have really burned the designers at Sun, because overriding operators isn’t in the language. Maybe the designers were offended that C++ overrode the bit-shift operators (<< and >>) for input and output. Maybe they came across a home-grown database system that used every operator under the Sun to perform tasks. Whatever the reason, it’s just not in the language.
Well, almost not in the language. As a convenience, they decided to throw C++’s unwashed masses a bone when it came to Strings. You get the ‘+‘ operator.
String a = "Hello " + "World!";
Do you feel the wind rushing through your hair yet? Me neither.
According to the documentation this is just syntactic sugar, as Java treats this as using StringBuilder or a StringBuffer along with append methods.
Consequences
In the event that you don’t think that the lack of operator overloading is harmful, let’s consider the discriminant in the quadratic formula.
// a, b, c are floats discriminant = b*b - 4*a*c;
This looks pretty easy, right? Now let’s look at it as a BigDecimal:
// a, b, c are BigDecimals discriminant = (b.multiply(b)).subtract((BigDecimal(4)).mult(a).mult(c));
This doesn’t look awful, but saying that it’s as readable as the normal arithmetic example is wrong. You could try to make it as neat and pretty as you can by commenting and indenting and spreading it out. I would, within reason. Do you think that this still doesn’t look bad? Then try doing the cubic formula. Or the quartic. The syntax is going to get in your way.
For big or complex implementations, this can be a pain in the ass. It becomes its own issue for the programmer, and gets directly in the way of actually solving problems.
People are the Problem
What is the problem? The cop-out answer is “People!”. To elaborate, we first need to look at the reasons that programming languages exist.
- So that people can efficiently talk to the computer.
- So that people can read how other people talk to the computer.
That’s it. There are no more reasons. If you think there might be, consider whether your reason is a reason or a consequence: I.E. programming language a has a problem, and programming language b was created to solve that problem. Programming languages help us quickly define and solve problems, and they exist so that other people can easily work on the problems based on what we wrote. Operator overloading deals directly with the readability of a language.
On one hand, overloading is very useful. For example, it fits perfectly into the C++ paradigm; the programmer does a little bit more work so that the user doesn’t have to. It fits well into Python’s paradigm, as it lets you get things done. If I knew anything about Ruby (and I’m reading enough Ruby blogs that it looks like I might start this summer when I have free time), it might fit into that.
It’s entirely syntactic sugar, and exists so that humans don’t yell “UGGGGH!” when they have to type in a huge formula for arbitrary precision arithmetic. If you have a BigInteger, why shouldn’t you be able to overload the + operator?
On the other hand, people will take any advantage that you give them, and they will abuse the hell out of it. They will either forget to update comments when they change the class, or they might just directly lie. They will swear on a stack of Bibles not to modify the data of a member you just passed, and then will use a const_cast<> and do it anyways. They will make gigantic utility classes named Utility that performs every function they know of. They will create 75 overrides of the same function that do entirely different things. All of these are supported by Java and/or C++, and the language does nothing to stop it.
All of these abuses are very easy for a person to perpetrate. We’ve all done at least one at some point or another. Our programming languages allow abuses with no hesitation, and some of these are committed extremely frequently. You can’t even remove the possibility of these abuses because some things, like commenting, are free-form, and could contain anything.
The Solution to Java’s Woes
I always feel bad complaining about something without trying to come up with a solution (one of the skills from my reading comprehension toolkit) so I tried to develop a Java-y solution that lets you overload operators while still “protecting the programmer from himself”. My solution is based on a single premise and two added constructs.
If we let the programmer override the base functions multiply(), divide(), subtract(), and add(), they will be allowed to use the overloaded operators (it’s not my fault/problem the designers of ArrayList used add instead of append() or insert()). For our discriminant example, this means that we are able to write
as we would expect to if BigDecimal had multiply overridden. It will just automatically be called.
Now, here is the premise that will hold it all together.
- You can only use type a’s operators with other objects of type a.
In order to make this useful, a second construct will be added to classes, the convert() construct. Let’s say the user wants to add two different types, such as the following example:
BigDecimal a; BigInteger b; a = a + b;
The user will have to override the convert() method in BigDecimal. The class would end up looking like this:
class BigDecimal{ public static BigDecimal add(BigDecimal a){ // ... } public static BigDecimal convert(BigInteger a){ // ... } }
The example would then be expanded to the following:
BigDecimal a; BigInteger b; a = a.add(BigDecimal.convert(b));
There we go, it’s easy! The Java compiler/interpreter can automatically perform this work just as it does for the String. It’s really no different, the mechanism is already built into the language. All that’s missing is order of operations, and that could easily be taken care of by processing the lines with a few passes.
If you don’t like this, what’s your way?
Popularity: 49% [?]
Comments
8 Responses to “People are the Problem, not Operator Overloading”
Leave a Reply

You might want to investigate Haskell’s type classes: http://www.haskell.org/tutorial/classes.html
I’ve played around with Haskell before, but never enough to learn the details of the type system. I just worked through the site you linked to, and it looks like they have some neat ideas. Thanks for the link!
I don’t know Java but I do know some c++ and I cannot believe that Java doesn’t support operator overloading! Shouldn’t operator overloading be number 1 in the feature request list ?
Assume for a moment that BigDecimal and BigInteger had both been added to the stuff you can use with the operators years ago. The fact that it hasn’t is quite a blight on sun’s java design team, but, stay with the hypothetical for a moment.
How important is operator overloading now?
I’d say: It isn’t. There’s something to be said for giving programmers the ability to write ‘eloquent’ libraries (a.k.a. DSLs), but operator overloading by itself isn’t nearly enough to get there. You’d have to change a lot more. ‘just’ operator overloading doesn’t seem to be useful, with the caveat that BigDecimal and BigInteger are added to the fold.
Having said that, if operator overloading is going to happen, strict requirements of type homogenity sound like an excellent idea.
I use a language where functions can have any name you want. Almost all of Java is prefix already. It seems silly to switch to infix just for arithmetic, when you need to wrap everything in (prefix) BigInteger calls to be guaranteed correct results, anyway.
Of course, I also use a language with built-in bignum support. I can’t imagine having to worry about silent overflow again. We solved that problem 40 years ago, and solved it efficiently 20 years ago.
Special-case “operators” are the problem.
Reiner: new Dollar(5) + new Dollar(10)
yesterday = Date.today() - new Day()
Maybe I missed your point…but there are many data types that you’d like to use in mathematical expressions.
You’re pretty much right on. I’m 67. Treat me as if I’m still learning, not as if I’m a child.
[...] has been pointed out before [shameless self-reference], one of the main reasons that we have programming languages is to show other people how we talk to [...]