Operator Overloading

Giving distinct meaning to operators depending on the type of their operands.

For example, compare the normal meaning of "+":

  int a = 2;
  int b = 3;
  int c = a + b; // c becomes 5.

with the "overloaded" meaning:

  string a = "Operator";
  string b = "Overloading";
  string c = a + b; // c becomes "OperatorOverloading"

A trait of CeePlusPlus, SmalltalkLanguage, RubyLanguage, DylanLanguage, and AplLanguage, among others.

OperatorOverloading and Polymorphism in general are mechanisms to allow one syntax to mean many things based on context. In this case, the context is the types of the parameters, though it is also useful to allow for context to include the type of the result. Operator overloading does not casually allow for the following: (a) altering operator precedence based on the types of the operators, (b) new operators. These require the ability to describe new syntax.

I find OperatorOverloading to be a constant source of errors and frustration. What's wrong with words?

Use of mathematical symbols can be clearer than words in mathematical expressions. See the CeePlusPlus below for an example. You also don't have to remember whether a particular class uses "a.add(b)", "a.plus(b)", "a.Plus(b)", "a.addedTo(b)", "sum(a, b)", etc.

Besides, words are also operators. They just happen to use special characters... the alphanumeric set... to identify themselves. And they, too, can be overloaded.

I like OperatorOverloading best when all of the overloading instances obey the same algebraic laws. For example, I prefer languages in which a+b is always equal to b+a, which is true for the usual overloadings of "+" to integers and floating point numbers, but not for the above overloading to strings. On the other hand, I'm a mathematician, so I don't expect a*b to always equal b*a (because it's not true for quaternions or matrices), so it's fine in my book to overload "*" to string concatenation. Plus, you naturally get "x"^4 = "xxxx" when you do things this way. The language I'm designing (OnceProgrammingLanguage) automatically inforces this convention. -- ThomasColthurst

CeePlusPlus allows you to do bizarre things with operator overloading, such as:

 class Foo {
	int x;

public: // insert appropriate ctor, dtor here bool operator == (const Foo &rhs) const { return x != rhs.x; // !!!; == is BACKWARDS } bool operator != (const Foo &rhs) const { return *this == rhs; // !!! != same as == } };

Great way to confuse people....

engineer_scotty (Scott Johnson)

I used to argue with people against operator overloading using arguments like these. They will claim operator overloading is bad, because you can't prevent people overloading the + operator to really do a subtract operation. My respond was: So what? How do you prevent people writing an add() function that really do a subtract? Anyway, I used to like operator overloading, but no longer, because couple with C++'s autocasting rules, it is a really difficult to see if a, say '=', is really doing a normal C++ operator thing or go called to an overloader operator method. -- OliverChung

Agreed. It's possible to name your variable foo, bar, and baz, or define a function named "printObject" that really deletes the hard disk, or eliminate all whitespace and indentation from the program. We don't suggest getting rid of variables, functions, and whitespace-neutral languages. I'd much rather have programming language features that let me do things I should do than prevent me from doing things I shouldn't. -- JonathanTang

Programmers that wish to intentionally obfuscate their code will -always- be able to find a means to do so. Something like the above depends on WorseThanFailure, and it'd be a good reason to send a programmer (or the maintainer who comes after) to a psychotherapist, but it still isn't a good reason to take away the power to modify syntax and operators for the domain. If you want to avoid that sort of mess, use conventions and code-reviews.

I want to have as few operators in my code as possible. I don't want to keep track of what they do in which class. If what they do is interesting I want a method name to explain it. -- EricHodges

But what if what they're doing really is "add", "subtract", "multiple", and "divide"? The most recent example was this year's IcfpProgrammingContest, where we were given definitions for fixed point math that we had to use in our simulations. The code was much clearer when I could define a class <fixed-point> and operators \+, \-, \*, and \/ that worked on it than if I'd had to spell out functions and use PrefixNotation. -- JonathanTang

Then you should spell them in the long way.

 class Fixed {
    Fixed sin() {
        Fixed x = this;
        if (x.compareTo(0) < 0) {
            return x.negated().sin().negated();
        if (x.compareTo(PI_DIV2) > 0) {
            return PI.minus(x).sin();
        Fixed x2 = x.multiply(x);
        Fixed x3 = x.multiply(x2);
        Fixed x5 = x3.multiply(x2);
        Fixed x7 = x5.multiply(x2);
        return x.minus(x3.divide(6)).add(x5.divide(120)).minus(x7.divide(5040));

Or do you think that this is better?

 class Fixed {
    Fixed sin() {
        Fixed x = this;
        if (x < 0) {
            return -(-x.sin());
        if (x > PI_DIV2) {
            return (PI - x).sin();
        Fixed x2 = x * x;
        Fixed x3 = x * x2;
        Fixed x5 = x3 * x2;
        Fixed x7 = x5 * x2;
        return x - (x3 / 6) + (x5 / 120) - (x7 / 5040);

The operators could be confused with the mathematical ones and... Hey, wait a minute, I'm doing math here. Thankfully I wasn't using some language whose designers know better than me which numeric types I'll ever need. -- DanielYokomiso

I'm much better at spelling out functions and using prefix notation than keeping track of what an operator means in a given statement. The above example is trivially easy to understand because it deals with only one class. Add a few more classes with their own overloaded operators and let the code sit for 6 months. Then try to remember which implementation of each operator will be used in each instance, what will autocast, etc. -- EricHodges

The above example trivially easy to understand is the specification for sine function from IcfpProgrammingContest 2003. As a JavaLanguage professional programmer I find it difficult to keep track of which method will be called in a given context, which will get automatic conversion, etc. in most of code I see other people write. If you have bad programmers they'll write 'fred = 'a.foo.bar.baz(); barney = fred.baz().cddar().car(); and you'll have no idea where the sql insert is being executed, without understanding the classes involved. People complain about operator overloading because CeePlusPlus programmers tend to find bizarre ways to use them (e.g. in >> x >> y;''? Of course it's a good idea!) but we never see SmallTalk or Haskell programmers complaining. If we are expressing math, we should be able to use math symbols (I would argue for |x| for abs and true sqrt symbols...), or else write code difficult to verify later. Don't cripple the language because of bad programmers. -- DanielYokomiso

But I can click Refactor>Rename on a, foo, bar, baz, cddar and car once I figure out what they mean and give everyone else a hint. I'd probably do the same if I found some overloaded operators (assuming my IDE supported that.) -- EricHodges

Limited operator overloading, I have no objection to... part of the discipliner of being a good C++ programmer is not abusing its many features; OperatorOverloading is one rife for abuse. (It is, after all, SyntacticSugar; and one which is especially known to cause gingivitis and tooth decay). A couple rules to follow:

Some languages, including HaskellLanguage, OcamlLanguage, PrologLanguage, and SmalltalkLanguage allow the user to provide their own operators, where an operator is a string of punctuation characters which can be used with infix/postfix/prefix syntax, rather than the standard "function call" syntax. (LispLanguage too, I guess, though it treats punctuation pretty much like any other atom).

In Smalltalk, only binary operators can be provided; and they all have the same precedence and associativity (left-associative). This is fine once you get used to it, but it's confusing at first in that

3 + 4 * 5

is 35 in Smalltalk, 23 in everything else.

Haskell and Prolog both allow defining new operators (both unary and binary), and also allow the associativity and precedence of such operators to be specified. Precedence in both language is specified by a (somewhat arbitrary) "precedence number".

Note that in Haskell, OCaml, and maybe others, you don't really have operators "overloading", because, like functions, operators can only be defined once, with one definite type. So you can't arbitrarily define multiple operators with different signatures in the C++ or Java way (which is ad-hoc polymorphism). Haskell, OCaml, etc. have polymorphic functions (parametric polymorphism); so they also have polymorphic operators; but that is not overloading as there is still just one operator implementation that works on all types. Also, Haskell has type classes, and type classes can include operators in their specification, and instances of the type class provide their own implementations of these operators. However, this also does not count as "overloading", because this is just providing an implementation for the type class; there is still just one operator, which belongs to the type class; and implementations are bound by the contract of the type class, so the different implementations are in effect the "same operation". Similarly in OCaml, different modules can define the operators with the same name, but they are in different namespaces.

Criteria ( http://mephle.org/Criteria/ ), a RubyLanguage library for constructing queries on datasets, uses a lot of heavy-duty overloading. Here's an example from its docs:

 idx1 = SQLTable.new("orders")
 q1   = (idx1.price > idx1.paid) & (idx1.duedate < Time.now.to_i)
 q1.limit    = 5
 q1.order    = :ASC
 q1.order_by = idx1.name, idx1.age
 puts q1.select
 # => SELECT * FROM orders WHERE ((orders.price > orders.paid) AND
 #    (orders.duedate < 1062616643)) LIMIT 5 ORDER BY orders.name,
 #    orders.age ASC

To do what it does, Criteria overloads methods such as "<", ">", and "&". It's definitely useful to some; in the (currently small) Ruby community there are a lot of people who do it. But when you do this in a language that isn't Smalltalk or Lisp you slam into the limitations pretty quickly. I tried doing something similar with my object-relational library, but found that you can't make code that looks like

 query = get_query( Product ) { |product| product.name != 'Sofa' }
 puts query.to_sql
 # => "select * from products where (product.name != 'Sofa' )"

Because you can override "<", but you can't override "==", and "!=" is just the unary negation of "==" and you certainly don't get to override unary negation in Ruby. Ah, well. -- francis

You can do this in Ruby, at least in 1.8, but you have to do some (ugly?) tricks if you want to preserve operator symmetry:

  Class query
    def == (rhs)
      ... comparison code

Class String def == (rhs) if (rhs.class == query) return (rhs == self) else return super(rhs) end end end

But it's not a totally unreasonable way to do it. Could be more elegant in a more strongly typed language, but then it wouldn't be Ruby. --dga

In C++, overloading can be an important technique to facilitate the use of templates. If two otherwise unrelated classes A and B are both acceptable parameters for overloaded function f(), then you can write generic algorithms parameterized on type T which invoke f(), and expect them to work when T is either A or B.

This is true more so when writing generic algorithms which are to accept both user-defined types and the C++ native types. Since C++ offers no way to extend the functionality of native types, programmers are forced to write user-defined types that can act as if they were native types, requiring operator overloading.

An especially useful example is the function template pattern, intimately related to FunctorObjects:
 class foo {                                    
	/* ... */
	template <typename Function>
	void Operate(Function &func) {
		func( mSomeVar );
This obviously achieves extremely loose (watery? prolapse?) coupling while providing type safety and most importantly the ability to use both actual functions and FunctorObjects.
It is both incorrect and misleading to include Smalltalk in the enumeration of languages that support OperatorOverloading at the top of this page. Smalltalk doesn't have operators, and therefore by construction does not have OperatorOverloading. Instead, Smalltalk has methods. OperatorOverloading is needed in CeePlusPlus because CeePlusPlus distinguishes between "operators" and "methods".

Not really that true any more. Certainly true in C; but in C++ operator overloading (indeed, most operators) can be (most of the time) be viewed as SyntacticSugar.

The expression a + b is equivalent to a.operator+(b) if a is an object; otherwise, it is (almost) equivalent to operator +(a,b) if a is not an object but b is an object or enum. The only place this breaks down is if both a and b are fundamental types; the compiler disallows int a=3,b=5,c; c = operator+(a,b);

In many other languages mentioned above (Haskell, Prolog), operators are SyntacticSugar; for every operator there is an equivalent "function call" form.

This distinction is, in turn, is driven by the distinction between "native" and "object" data types. Native types, in CeePlusPlus, aren't objects -- therefore they don't have classes, don't have methods, and therefore can't be specialized.

They can be partially specialized with the freestanding form mentioned above. I can't define int::operator + (const Foo&) to allow adding an int to a Foo, but I can define operator +(int, const Foo &). C++ doesn't allow redefining operations on the standard types; part of C/C++ culture is that mutating the language is a BadThing. (Smalltalk culture differs on this point).

OperatorOverloading attempts to allow the CeePlusPlus programmer to simulate method dispatching.

Or the other way around. Certainly, if you provide overloaded operators for a class, under the hood a method dispatch is used.

The CeePlusPlus OperatorOverloading mechanism is syntax, wired into the compiler. The mechanism cannot be changed without modifying the compiler. The mechanism is different from the method dispatch in CeePlusPlus. I'm not saying this is bad or good, it simply is.

The binary selectors in Smalltalk are just method selectors, recognized by the compiler. These messages can be overridden, added to, changed, and everything else. There is no difference in system behavior between a method body whose selector is "+" and the same method body with selector "#plus:".

Likewise, there is no real difference between a + b and a:operator+ (b), when a is an object. You are correct in that non-objects aren't handled quite as cleanly. But for objects, operator overloading can be viewed as SyntacticSugar for method calls.

This means that, for example, a ComplexNumbers class can be added to the Smalltalk environment and readily wired into the numeric hierarchy, where it can then participate in conventional arithmetic with the other numeric types already supported. In the commercial and financial domains, this ability has been put to great use to support various numeric types including BinaryCodedDecimal, ArbitraryPrecisionDecimal? (BigInt), ArbitraryPrecisionFloatingPoint? (BigNum), and similar constructs.

In both languages, you still have the DoubleDispatch problem. Which is orthogonal to whether you type a + b, a.operator +(b), or a #plus: b

A limitation of the Smalltalk approach is that it is not possible to embed a binary selector or other special character (+, /, \, *, ~, <, >, =, @, %, |, &, ?, !) into a keyword or unary selector (at least according to BlueBook Smalltalk).

It is not helpful to glom together fundamentally different behaviors under buzzwords like OperatorOverloading.

In my opinion, BinarySelector?s and OperatorOverloading are closer cousins than you think.
See also OverloadingCommaOperator, PlusSignOverloading
CategoryLanguageFeature CategoryCpp CategoryRuby

View edit of May 27, 2014 or FindPage with title or text search