I for one welcome our operator overloads... um, overlords... uh...
[segmentation fault]
Seriously, what's the difference? If you don't have operator overloading, then you have to call a function. And an overloaded operator is a function call. So what's the difference?
You can overload + to add matrices, say. That could allocate. It could also be buggy and subtract them instead. Or, you could call AddMatrices, which could also allocate, and could also be buggy and subtract the matrices.
The only difference is that, if you came from C, you might expect + to be the built-in arithmetic operator, and only that. That is, if you don't know the language, then the language features may surprise you. That's... not news, and not very interesting.
I agree with the article. The complainers have a C hammer, and they can't see beyond it.
I think the article to which the linked article is responding is a bit of a broken clock... that is, it's correct about operator overloading being detrimental, but their reasoning is incorrect.
The questions about allocation and garbage collection are irrelevant for the reasons you mention. But operator overloading allows problematic code for another reason.
`AddMatrices` is unambiguous; clearly its operands should be matrices, and they should be added according to matrix arithmetic rules (and, like you said, if the underlying code is buggy, it would also be buggy as an overloaded operator). The problem is that `+` is ambiguous. And if you're dealing with matrices, you're probably looking at code written by a math person, meaning it's going to be shorthand-heavy and the operands' names are unlikely to make the variables' types clear.
But at least in the matrix vs. scalar case, you have a similar set of axioms, so changing `x + m` to `m + x` should not alter the result regardless of the types. This is not so when people shove even more meanings onto a single operator, like `+` for string concat. String concatenation doesn't commute. Furthermore, different languages have different rules for "adding" one string and one number, so it causes needless friction for polyglots.
I'm not saying I prefer `concat(s1, s2)`, because I like my operators. I'm saying I prefer something like Raku's `~`. As an added bonus, you get automatic and consistent coercions. You know exactly what the operation is and how the operands will be treated when you see `~`, with no need to find the operand types.
In conclusion, operator overloading is a half-assing of full-fledged user-defined operators, and it encourages programmers to shove disparate functionalities (often with different axioms) into the same operator. Either let people write traditional functions, or give them the ability to create their own operators so they're not tempted to make a mess of the default set of operators.
In part I agree. If you have "a + b", and a and b are Employees, what does that even mean? Does it commute? Who knows?
But "adding" strings specifically, that idiom is I think sufficiently well established that it's in the category of "know the language - you're not in C anymore".
I want operator overloading. I want to be able to use + for adding, say, quaternions with integer components modulo n. (I also like my operators.) I want to be able to use | for or of fuzzy booleans defined as reals on the closed interval [0, 1].
I don't want + for Employees. But given what I do want, I don't see how anything other than good taste can allow the one and prohibit the other.
I didn't realize that concatenating two strings was the same exact concept as adding two numbers together.
You learn something new everyday.
Oh, they're not?
Then why are you using the same operator?
...
They reused the operator because you can say in English that “you are adding two strings together”, and have it be a perfectly reasonable sentence to say. As the designers were English speaking, it made enough sense to them to add it to that operator. If they spoke a different language, who knows what operator they would have used instead.
A better idea would be to allow people to add new operators. Even better if you can use that same feature to extend existing operators where it makes sense.
The reason few languages allow that is that their parsing system is still largely designed around the memory and speed tradeoffs that were required in the 1970s. As such it is difficult to alter the parser while it is parsing.
Raku has this feature, and it works by subclassing the current parser to add new operators. (It's intended that you can also temporarily replace it for one that parses an entirely different language.)
So, do you want to have addIntegers, addUnsignedLongs, addFloats, etc. too?
You would need to have those or separate operators in some strongly typed languages that do not automatically coerce ints to floats, etc.
Also, for floats, a+b == b+a, but you don’t necessarily have a+b+c == c+b+a. So, if you’re strict in that “should not alter the result regardless of the types”, you would have to forbid using + on floats in some more complex expressions.
Finally, I don’t see how “operator overloading […] encourages programmers to shove disparate functionalities (often with different axioms) into the same operator.” is much different from “function overloading […] encourages programmers to shove disparate functionalities (often with different axioms) into the same function”.
It should maybe noted that all operators in Raku (excapt the short-circuiting || and && and friends) are in fact "user" defined operators. They just happen to be defined already every time you start a Raku program. But code-wise, there is no difference!
Re operator overloading: you could argue you could also do that in Raku, but generally it is about adding functionality. See e.g. the Interval module, which adds "interval" knowledge to the standard DateTime object. It also adds functionality to the + and - infix operators. See: https://modules.raku.org/dist/Interval/lib/Interval.pm6
I like the latter better than the former, but it's not like one is complete evil and the other is great.
Instead the issue with C++ is more complicated. It's a perfect storm of:
1. Easy to pretend it's "just like C" when really the increased quantity of features combine to make a major qualitative difference in how to use the tool
2. A large number of features that subtly (and sometimes not so subtly) encourage the programmer to do the wrong thing; many of the library changes from C++11 and on are about deprecating such features.
3. A lot of poorly implemented compilers for the first 20 years of its existence (when Alexandrescu's book came out, no existing compiler could compile all of the examples properly).
4. #2 and #3 combined to cause a lot of companies to choose their own (mutually incompatible) subset of C++'s features in the 90s.
#4 and #1 meant that C++ programmers regularly couldn't read code written by other C++ programmers. At some point, a subset of them stopped blaming "other C++ programmers" and started blaming the language.
7 comments
[ 4.4 ms ] story [ 23.5 ms ] thread[segmentation fault]
Seriously, what's the difference? If you don't have operator overloading, then you have to call a function. And an overloaded operator is a function call. So what's the difference?
You can overload + to add matrices, say. That could allocate. It could also be buggy and subtract them instead. Or, you could call AddMatrices, which could also allocate, and could also be buggy and subtract the matrices.
The only difference is that, if you came from C, you might expect + to be the built-in arithmetic operator, and only that. That is, if you don't know the language, then the language features may surprise you. That's... not news, and not very interesting.
I agree with the article. The complainers have a C hammer, and they can't see beyond it.
The questions about allocation and garbage collection are irrelevant for the reasons you mention. But operator overloading allows problematic code for another reason.
`AddMatrices` is unambiguous; clearly its operands should be matrices, and they should be added according to matrix arithmetic rules (and, like you said, if the underlying code is buggy, it would also be buggy as an overloaded operator). The problem is that `+` is ambiguous. And if you're dealing with matrices, you're probably looking at code written by a math person, meaning it's going to be shorthand-heavy and the operands' names are unlikely to make the variables' types clear.
But at least in the matrix vs. scalar case, you have a similar set of axioms, so changing `x + m` to `m + x` should not alter the result regardless of the types. This is not so when people shove even more meanings onto a single operator, like `+` for string concat. String concatenation doesn't commute. Furthermore, different languages have different rules for "adding" one string and one number, so it causes needless friction for polyglots.
I'm not saying I prefer `concat(s1, s2)`, because I like my operators. I'm saying I prefer something like Raku's `~`. As an added bonus, you get automatic and consistent coercions. You know exactly what the operation is and how the operands will be treated when you see `~`, with no need to find the operand types.
In conclusion, operator overloading is a half-assing of full-fledged user-defined operators, and it encourages programmers to shove disparate functionalities (often with different axioms) into the same operator. Either let people write traditional functions, or give them the ability to create their own operators so they're not tempted to make a mess of the default set of operators.
But "adding" strings specifically, that idiom is I think sufficiently well established that it's in the category of "know the language - you're not in C anymore".
I want operator overloading. I want to be able to use + for adding, say, quaternions with integer components modulo n. (I also like my operators.) I want to be able to use | for or of fuzzy booleans defined as reals on the closed interval [0, 1].
I don't want + for Employees. But given what I do want, I don't see how anything other than good taste can allow the one and prohibit the other.
Oh, they're not?
Then why are you using the same operator?
...
They reused the operator because you can say in English that “you are adding two strings together”, and have it be a perfectly reasonable sentence to say. As the designers were English speaking, it made enough sense to them to add it to that operator. If they spoke a different language, who knows what operator they would have used instead.
A better idea would be to allow people to add new operators. Even better if you can use that same feature to extend existing operators where it makes sense.
The reason few languages allow that is that their parsing system is still largely designed around the memory and speed tradeoffs that were required in the 1970s. As such it is difficult to alter the parser while it is parsing.
Raku has this feature, and it works by subclassing the current parser to add new operators. (It's intended that you can also temporarily replace it for one that parses an entirely different language.)
You would need to have those or separate operators in some strongly typed languages that do not automatically coerce ints to floats, etc.
Also, for floats, a+b == b+a, but you don’t necessarily have a+b+c == c+b+a. So, if you’re strict in that “should not alter the result regardless of the types”, you would have to forbid using + on floats in some more complex expressions.
Finally, I don’t see how “operator overloading […] encourages programmers to shove disparate functionalities (often with different axioms) into the same operator.” is much different from “function overloading […] encourages programmers to shove disparate functionalities (often with different axioms) into the same function”.
Re operator overloading: you could argue you could also do that in Raku, but generally it is about adding functionality. See e.g. the Interval module, which adds "interval" knowledge to the standard DateTime object. It also adds functionality to the + and - infix operators. See: https://modules.raku.org/dist/Interval/lib/Interval.pm6
Instead the issue with C++ is more complicated. It's a perfect storm of:
1. Easy to pretend it's "just like C" when really the increased quantity of features combine to make a major qualitative difference in how to use the tool
2. A large number of features that subtly (and sometimes not so subtly) encourage the programmer to do the wrong thing; many of the library changes from C++11 and on are about deprecating such features.
3. A lot of poorly implemented compilers for the first 20 years of its existence (when Alexandrescu's book came out, no existing compiler could compile all of the examples properly).
4. #2 and #3 combined to cause a lot of companies to choose their own (mutually incompatible) subset of C++'s features in the 90s.
#4 and #1 meant that C++ programmers regularly couldn't read code written by other C++ programmers. At some point, a subset of them stopped blaming "other C++ programmers" and started blaming the language.