Could the Java community be right?

Why can't authors get operator overloading right?

© Conrad Weisert, October 4, 1999

Readers of these pages know that we strongly disagree with the opinion of many in the Java community about the value of overloaded operators.

". . . The language designers decided (after much debate) that overloaded operators were a neat idea, but the code that relied on them became hard to read and understand."—David Flanagan: Java in a Nutshell, 1996, O'Reilly & Associates, p. 35.
"One of the major problems with operator overloading is that it gives the programmer the power to easily write code that is difficult to read."—Paul Tyma, Gabriel Torok, and Troy Downing: Java Primer Plus, 1996, Waite Group Press, p. 254

If you're not convinced of the absurdity of such views, take a look at Conventions for Arithmetic Operations in Java or The Dark Side of Java.

It would be easier, however, to refute such views if more C++ courses and textbooks contained applications of the sensible and consistent use of overloaded operators. Unfortunately, most C++ books merely describe the mechanics or how overloading works, and give only fairly trivial examples. Worse, when they do offer examples, they're often badly flawed and only serve to strengthen the arguments of the anti-overloading crowd.

Let's look at three examples in books that I otherwise admire and recommend.

1. Violating high-school arithmetic

A well respected advanced C++ textbook uses Complex arithmetic to introduce a numeric class with operator overloading. One version of the class (presumably not meant as a serious proposal) postulates a companion pure Imaginary class. The author then proposes these operation declarations inside the Imaginary class:

        Imaginary operator* (const Imaginary &c);
        Imaginary operator/ (const Imaginary &c);

James O. Coplien: Advanced C++ Programming Styles and Idioms, 1992, Addison-Wesley, p. 224.

I often give that example to my students, who, recalling from elementary algebra that the result of multiplying an imaginary by another imaginary is a real number, almost always figure out that what the author undoubtedly meant was:

        Imaginary operator* (const double x);
        double    operator* (const Imaginary &c);
        Imaginary operator/ (const double x);
        double    operator/ (const Imaginary &c);

The exercise is instructive, and it reminds the student that even senior professionals slip up.


2. What date is July 4, 1776, plus December 7, 1941?

Many textbooks use Date to illustrate a numeric class. Unfortunately, they either don't illustrate date arithmetic at all or they get it wrong. For example:

          Date operator+(const Date &d1, const Date &d2); 

Danny Kolev: The ANSI/ISO C++ Professional Programmers' Handbook, 1999, Que Publishing, p. 48.

Now, we can ask a beginning programming class what they think it means to add one date to another, and they almost always deduce correctly that such an operation yields nonsense. Someone may point out that if we interpret one of the "dates" as a duration the answer makes sense. But then we show them that the object-oriented paradigm is supposed to protect the programmer from misinterpretations of data, and that we can easily develop a duration class. We may choose to approve a compromise, using pure numbers instead of a duration class:

     Date operator+(const long n,   const Date &d2); 
     Date operator+(const Date &d1, const long n); 

(For a complete explanation of this example and the next one see The Point Extent Pattern for Dimensioned Numeric Classes, ACM SIGPLAN Notices, November, 1997.)


3. Gang of Four in Two Dimensions

Here's a longer example, quoted verbatim but condensed to eliminate irrelevant parts:

Point represents a point in a two-dimensional Cartesian coordinate space. . . . Point's operations are self explanatory.


 typedef float Coord; 
 class Point  {
 public:
   Point(Coord x=0.0, Coord y=0.0);
   
   friend Point& operator+(const Point&, const Point&);
   friend Point& operator-(const Point&, const Point&);    
   friend Point& operator*(const Point&, const Point&);
   friend Point& operator/(const Point&, const Point&);
    .
    .
  }; 

Gamma, Helm, Johnson, and Vlissides: Design Patterns, 1995, Addison Wesley, appendix C4.

First consider what it means to add one point to another. The result is nonsense, unless we agree, as was proposed for Date to interpret one of the points as a distance vector. OK, let's concede that, even though an object-oriented designer will surely prefer to design a Distance class for that purpose.

But even if we stretch our interpretation of Point to permit addition and subtraction, what on earth does it mean to multiply or divide one point by another point? What do you suppose the authors had in mind when they asserted that Point's operations are "self explanatory"?


Still looking for a textbook

Operator overloading isn't difficult or mysterious. Hasn't someone written a sensible treatment with examples in a textbook? If you know of one, please let me know (see home page for E-mail and telephone numbers).

Addendum, 2005

I gave up looking for an adequate textbook presentation of this topic and repackaged my course handouts. Object-Oriented Computation in C++ and Java (Dorset House) will be available this summer.

Authors' responses

The three books from which I drew the above examples are well regarded and I intend no condemnation of the authors, only disappointment. Nevertheless, I'm happy to append any author's comments or any other informed opinion to this article.

In the January, 1996, SIGOOT1 Newsletter, James Coplien vigorously defended his Imaginary example on the grounds of "efficiency". This July, I sent an inquiry to the Design Patterns authors using the E-mail address given in their book, but got no reply.


1 -- Special Interest Group for Object-Oriented Technology, an informal Chicago organization that flourished in the 1990s, now defunct.

Last Modified February, 2016 (minor format changes)

Return to technical articles
Return to IDI home pages