I dislike when people use the term “power” to describe making code slightly shorter to type. Operator overloading is not in any meaningful sense more powerful than a language which lacks it.

You say that because you lack experience in writing programs for scientific-technical computing, where an abundance of complicated mathematical formulae are necessary.

Most programmers have seen only programs that do more data movement and comparison than actual computation, but nonetheless there are programs with abundant computations, the kind of programs that were originally written in Fortran, but nowadays they may be ported to other languages, or alternatives for them may be now written in more modern languages.

In such programs, overloaded operators do not make programs "slightly shorter to type", but they reduce the amount of text at least an order of magnitude or even much more.

The main advantage is not that you type less, but that you can read the source of some function in one page, so you can see it in its entirety, instead of having the source spread on many pages, forcing you to wander through all those pages continuously, when you try to understand what it does and whether it does it correctly.

I have written such programs, for instance which were full of long formulae where most variables were complex vectors or complex matrices (for computing some radiated electromagnetic fields with the method of boundary elements). Without the operator overloading of C++, reading them would have been extremely tedious and maintaining them would have been very error prone.

For myself, any programming language that lacks operator overloading, e.g. Java, is disqualified, because it definitely is not "powerful" enough.

Operator overloading also increases the safety of a programming language, because you can define distinct data types for each kind of physical quantity, allowing the compiler to detect and reject the invalid operations. Without operator overloading that would inflate too much the size of the source text.

> where an abundance of complicated mathematical formulae are necessary

I think what you mean to say is, a lot of linear algebra is involved. So multi-dimensional structures like matrices and vectors are expected to have linear arithmetic operators defined over them, because they're used quite a lot.

You don't need operator overloading for that. Your language should be providing them as primitive structures and extending operators over them. Think like how C has a polymorphic addition, where '+' doesn't discriminate between integers, pointers and floats.

There are a lot of problems with user-facing operator overloading, but I think Haskell is actually a really great example of how to do it sanely. At the point in which you have type-families, you can properly restrict the semantic domain of a polymorphic function but still keep it an open set. The addition operator being restricted over types belonging to the Num type-family as an example trivially allows you to use '+' for matrix addition.

https://hackage-content.haskell.org/package/matrix-0.3.6.4/d...

Now you've avoided the worst part of user-facing operator overloading (juniors creating incoherent DSLs by abusing the mechanism) while still providing the mechanism where it's useful.

I agree with you on overloading - the real word here should be "expressivity", which is defined by language constructs that could NOT be syntactic sugared into a local context. Those may occasionally be useful, though not by itself. E.g. gotos are more expressive by the above definition, yet it was largely deemed to not be a useful "power".

Certain kinds of GOTOs are indeed proven mathematically to be necessary to write certain programs, in the sense that eliminating the GOTOs can be done only by making the program more inefficient, i.e. by increasing the number of executed instructions and the amount of memory that is used.

Because of this, any decent programming language must include GOTOs, but in many modern languages they are not named GOTOs, because of the bad reputation of the word.

For instance the language Scheme does not have GOTOs, but it has mandatory tail call optimization, which means that a "tail call" is just an alternative name for "GOTO". For example, this allows the writing of a state machine in Scheme, exactly like it would be written in a language with GOTO, but using tail calls instead of GOTOs.

Other languages have labelled loops and they allow exit a.k.a. break with a label and next a.k.a. cycle a.k.a. continue with a label. Such instructions with labelled targets are just GOTOs with a bad placement of the label, which makes reading the source more tedious than with a classic GOTO.

For providing the benefits of GOTO, a restricted variant is sufficient, i.e. a GOTO that may jump only forwards and which cannot jump inside nested blocks.

With operator overloading you can provide same numeric operation interface to library types such as big integers. Sure, you can also define methods and make sure your primitive types also define those methods but now you have some confusions (like equals vs == in Java).