Sorting out some of my current views on operator overloading in general

May 12, 2018

Operator overloading is a somewhat controversial topic in programming language design and programming language comparisons. To somewhat stereotype both sides, one side thinks that it's too often abused to create sharp-edged surprises where familiar operators do completely surprising things (such as << in C++ IO). The other side thinks that it's a tool that can be used to create powerful advantages when done well, and that its potential abuses shouldn't cause us to throw it out entirely.

In general, I think that operator overloading can be used for at least three things:

  1. implementing the familiar arithmetic operations on additional types of numbers or very strongly number-like things, where the new implementations respect the traditional arithmetic properties of the operators; for example + and * are commutative.

  2. implementing these operations on things which already use these operators in their written notation, even if how the operators are used doesn't (fully) preserve their usual principles. Matrix multiplication is not commutative, for example, but I don't think many people would argue against using * for it in a programming language.

  3. using these operators simply for convenient, compact notation in ways that have nothing to do with arithmetic, mathematical notation, or their customary uses in written form for the type of thing you're dealing with.

I don't think anyone disagrees with the use of operator overloading for the first case. I suspect that there is some but not much disagreement over the second case. It's the third case that I think people are likely to be strongly divided over, because it's by far the most confusing one. As an outside reader of the code, even once you know the types of objects involved, you don't know anything about what's actually happening; you have to read the definition of what that type does with that operator. This is the 'say what?' moment of << in C++ IO and % with Python strings.

Languages are partly a cultural thing, not purely a technical one, and operator overloading (in its various sorts) can be a better or a worse fit for different languages. Operator overloading probably would clash badly with Go's culture, for example, even if you could find a good way to add it to the language (and I'm not sure you could without transforming Go into something relatively different).

(Designing operator overloading into your language pushes its culture in one direction but doesn't necessarily dictate where you wind up in the end. And there are design decisions that you can make here that will influence the culture, for example requiring people to define all of the arithmetic operators if they define any of them.)

Since I'm a strong believer in both the pragmatic effects and aesthetic power of syntax, I believe that even operator overloading purely to create convenient notation for something can be a good use of operator overloading in the right circumstances and given the right language culture. Generally the right circumstances are going to be when the operator you're overloading has some link to what the operation is doing. I admit that I'm biased here, because I've used the third sort of operator overloading from time to time in Python and I think it made my code easier to read, at least for me (and it certainly made it more compact).

(For example, I once implemented '-' for objects that were collections of statistics, most (but not all) of them time-dependent. Subtracting one object from another gave you an object that had the delta from one to the other, which I then processed to print per-interval statistics.)

In thinking about this now, one thing that strikes me is that an advantage of operators over function calls is that operators tend to be written with whitespace, whereas function calls often run everything together in a hard to read blur. We know that whitespace helps readability, so if we're going to lean heavily on function calls in a language (including in the form of method calls), perhaps we should explore ways of adding whitespace to them. But I'm not sure whitespace alone is quite enough, since operators are also distinct from letters.

(I believe this is where a number of functional languages poke their heads up.)


Comments on this page:

From 78.58.206.110 at 2018-05-12 08:13:06:

Matrix multiplication is not commutative, for example, but I don't think many people would argue against using * for it in a programming language.

Oh, the arguments about matrix multiplication have actually gone to the point that Python now provides an @ operator just for that purpose, leaving * available for scalar multiplication. See PEP-465.

From 78.58.206.110 at 2018-05-12 12:50:48:

leaving * available for scalar multiplication

...by which I meant elementwise multiplication.

By Dave at 2018-05-12 19:38:26:

I believe most languages allow whitespace between the object and the method call:

For example, in python:

>>> x=[4,1,2]
>>> x . sort()
>>> x
[1, 2, 4]
By Ben C at 2018-05-27 17:04:49:

Operator overloading in Haskell is rather nice. It is a functional language but I don't think that's necessary for any of these features.

  • You can define new operators, for example @@. This avoids having to twist the meaning of an existing operator to do something completely different. (You can use Unicode symbols if you want to avoid ugly combinations of ASCII symbols!)

  • Overloading operators (and functions) is limited to type classes (like C++ concepts). For example, if you want to overload + for a type it needs to be an instance of the Num typeclass - which requires you to implement at least a few other functions and operators including * and abs.

  • You can use an operator as a prefix function by putting it in brackets, thus (*) 2 3 and 2 * 3 are equivalent.

  • You can use a function of two arguments as an infix operator by putting it in backticks, thus foo 1 2 and 1 `foo` 2 are equivalent.
Written on 12 May 2018.
« Notice to web spiders: an email address in your user-agent isn't good enough
ZFS on Linux's development version now has much better pool recovery for damaged pools »

Page tools: View Source, View Normal, Add Comment.
Search:
Login: Password:
Atom Syndication: Recent Comments.

Last modified: Sat May 12 00:39:36 2018
This dinky wiki is brought to you by the Insane Hackers Guild, Python sub-branch.