Reading blogs and forum posts, I have noticed that some developers clamor for operator overloading while others warn against it. On sites such as StackOverflow, Java developers will state that the lack of operator overloading is shortcoming in the language. Other developers hold that the inclusion of operator overloading in languages like C# and C++ creates possibility of making code both more difficult to understand and more difficult to debug. Which set of developers is correct?
Overloading an operator can be useful. Objects like vectors and matrices can have traditional mathematical operations performed on them, so overloading an operator to facilitate that operation is both clear and natural. Replacing an overloading operator with a function is less clear and natural. Visually the function simply looks too verbose. That verbosity can lead to unclear code. As a result, an overloaded operator can actually lead to cleaner code. Consequently, the ability to overload operators can be useful, so there is some merit to allowing it.
Although examples of clean code resulting from overloading operator exist, there are examples of silly uses of overloaded operators as well. For example, a coder could have both an operator and a function to achieve the same result. In a given expression, both the operator and the function could be used. For a person tasked with understanding or debugging such code, the duplication of functionality would be confusing. Both the operator and the function are used, yet they appear to be functionality equivalent. That confusion makes the task of understanding and debugging code more difficult. In order to determine whether both the operator and function are equal, the person who is reading over the code must look at both the operator and the function. That extra time and brain power is not well spent as that energy could be put into less silly aspects of the code. As a result, the absurdity that overloading operators allows has significant pitfalls.
Obfuscating functionality, however, is far more dangerous than absurd example above. Any experienced code would notice such a mistake and correct it by either removing the function or the overloaded operator. However, if overloaded operators obfuscate functionality, even an experienced developer may not be able to easily diagnose the issues in the code. Operations regarding vectors and matrices are clear, but operations involving objects such as people may not be. Granted, comparison operators are generally clear for most objects, but mathematical operations are not. A person cannot be multiplied by another person, yet overloading operators allows such code to be written. Faced with such a line of code, the debugger may have no clue as to what that line intends to accomplish. As a result, he or she will clueless as to whether such a line contributes to the problem to be solved. If the coder had used a function, the debugger would more easily be able to deduce the purpose of multiplying two people. The inclusion of an overloaded multiplication operator instead obscures that purpose. The work of the debugger is more difficult as a result. Clearly, overloading operators can be deleterious to a program.
//the code below is pseudo code
Vector v1 = new Vector(1.0f, 2.0f, 3.0f);
Vector v2 = new Vector(1.0f, 2.0f, 3.0f);
Vector v3 = v1 * v2; //clear intended use
v3 = multiplyVectors(v1,v2); //more verbose than the operator
v3 = v1 * multiplyVectors(v1,v2); //silly example
Person p1 = new Person(Person A");
Person p2 = new Person("Person B");
Person p3 = p1 * p2; //not sure what this is meant to do
Java clearly saw that danger and decided to forgo flexibility for safety. That decision has led to a language that makes it difficult to shoot yourself in the foot. A coder cannot overload an operator, so he or she cannot use it to obscure functionality. Coders are forced to be safe whether they like it or not. Given the mass of C++ programs built on backs of obscure uses of overloaded operators, Java’s decision to take away the “gun” from coders seems prudent. In forgoing flexibility for safety, was Java too cautious?
First, the question must be asked, “for whom is the language intended”? A language intended for inexperienced developers would be prudent to remove features, yet a language targeted towards experienced developers does not need to be so cautious. Why should a language give experienced developers the fully loaded gun? All developers make mistakes and even good ones produce poorly designed code at times. The experienced developer is much more likely to recognize a mistake when he sees it. More importantly, the experienced developer is also much more likely to recognize the potential for problems and avoid them. Consequently, the experienced developer is much less likely to use dangerous features dangerously and more likely to use those features in productive ways. As a result, If a language is to be used by experienced developers, the risk of including a feature like operator overloading may not be as great as one might think.
C++ and C# are not languages aimed people who have no clue how to code. A neophyte programmer is able to install an IDE and built simple programs in both languages, yet such a coder thoroughly lacks the skill to build a well-designed, complicated application in either language. Only an experienced developer is capable of completing such a task. The design of both languages assumes that the developer has the experience to build a well-designed, complicated program. As a result, the inclusion of operator overloading is not particularly dangerous.
Java is not a language aimed at inexperienced developers, yet Java left the ability to overload operator out. Why? The progenitors of Java probably did not fear that experienced developers would misuse overloaded operators, but still preferred that they not be included. Java chose to be safe rather than sorry. Hindsight cannot judge the designers to be wrong for not including operator overloading. Java has proven to be much safer language than C++ while still being highly functional. As a result, the designers of Java were more right than wrong.
Neither approach is correct. The safer approach taken by Java is less likely to yield bad results. However, the more flexible approach taken by C# and C++ allows developers to choose potentially cleaner solutions, but that flexibility can lead serious pitfalls. However, those pitfalls are likely to be avoided with an experienced development team. As a result, the superiority of safety over flexibility with regard to operator overloading is not exactly clear and highly dependent upon the experience of the development team. With regard to operator overloading, the approach of Java is not inherently superior to C# or C++.