views:

3931

answers:

15

Operator overloading in C++ is considered by many to be A Bad Thing(tm), and a mistake not to be repeated in newer languages. Certainly, it was one feature specifically dropped when designing Java.

Now that I've started reading up on Scala, I find that it has what looks very much like operator overloading (although technically it doesn't have operator overloading because it doesn't have operators, only functions). However, it wouldn't seem to be qualitatively different to the operator overloading in C++, where as I recall operators are defined as special functions.

So my question is what makes the idea of defining "+" in Scala a better idea than it was in C++?

+31  A: 

Operator overloading was never universally thought to be a bad idea in C++ - just the abuse of operator overloading was thought to be a bad idea. One doesn't really need operator overloading in a language since they can be simulated with more verbose function calls anyway. Avoiding operator overloading in Java made the implementation and specification of Java a little simpler and it forced programmers to not abuse operators. There has been some debate in the Java community about introducing operator overloading.

The advantages and disadvantages of operator overloading in Scala are the same as in C++ - you can write more natural code if you use operator overloading appropriately - and more cryptic, obfuscated code if you don't.

FYI: Operators are not defined as special functions in C++, they behave just like any other function - although there are some differences in name lookup, whether they need to be member functions, and the fact that they can be called in two ways: 1) operator syntax, and 2) operator-function-id syntax.

Faisal Vali
+34  A: 

Operator overloading in C++ is considered by many to be A Bad Thing(tm)

Only by the ignorant. It is absolutely required in a language like C++, and it is noticeable that other languages that started off taking a "purist" view, have added it once their designers found out how necessary it is.

anon
Steady on, mr grumpy pants
skaffman
I actually agree with Neil. Operator overloading is essential if you want to present variables/constants/objects/instances as algebraic entities... and have people understand their interactions in a mathematical fashion -- which should be how programming works IMHO.
Massa
+1, Operator overloading in C++ is good. For example it makes vector math a lot cleaner. Like with many C++ features, you should wield the power carefully.
abababa22
For another example, I've become used to how `<<` is used for streams. You could replace that operator with a method invocation, however I find `cout << "Hello " << name << "!";` is neater than `cout.print("Hello ").print(name).print("!");`
ChrisW
I agree that operator overloading can be very useful, but why is it "absolutely required" in C++?
Kristo
@Kristo Because C++ uses values that must be assigned and copied. It is necessary to have control over that, so you must be able to specify the assignment operator for a given type, at a minimum.
anon
@Kristo: because one intention of C++ is to allow user-defined types to do everything that builtin types do (albeit they're treated differently in some contexts such as implicit conversions). If you want to implement a 27-bit integer, then you can, and using it will be just like using int. Without operator overloading, it would not be possible to use UDTs with the same the syntax as builtin types, and hence the resulting language would not be "like C++" in this sense.
Steve Jessop
Neil's example being an important example: consider "int a(0); a = a + 1;". As C++ stands, I can do, "MyInt27 a(0); a = a + 1;". In C++ without operator overloading, that would have to be "MyInt27 a(0); a.set(a.plus(1));". Not exactly a drop-in replacement. So it would not be possible to write a template that works with either int or MyInt27, as required by the user.
Steve Jessop
Faisal Vali
@Faisal How would you implement std::string, as a class that can be used in a std::vector, without operator overloading, and without major changes to underlying C++ language semantics?
anon
@Neil - Well, to solve the issue with string, as an initial attempt, I would specialize vector for primitive (using operators) vs non-primitive (using appropriately named functions for assignment, ala C) types, keeping vector's interface consistent - but i agree that it would be ugly and unnecessary - i would curse the lack of operator overloading on a daily basis ;)
Faisal Vali
@faisal Oh come on now, you are not allowed to specialise a container for the contained! that way lies madness.
anon
@Neil well, I mostly agree with you - even with the use of adapters and just one specialization for non-primitive types, time is being spent very inefficiently.
Faisal Vali
"that way lies madness" - even worse, that way lies std::vector<bool>!
Steve Jessop
Here's a thought, though. You wouldn't have to specialise every container. Instead, all containers could wrap their contents in a class template Box. Box has methods "set", "compare", etc, which by default it just delegates to its contents. But Box (only) is specialised for arithmetic types to implement "set" with = and "compare" with <. One downside I can already think of is that vector<T> wouldn't be an array of T, it would be an array of Box<T>. But you could non-portably ensure Box<T> is storage-compatible with T, and that the reinterpret_cast to T* "just works".
Steve Jessop
But I think the fact that Java had to remove operator overloading; realise that they'd messed things up for generics; invent auto-boxing to fix the problem; is a clear indication that C++ is doing something right. The one clear argument I know against operator overloading is that if you don't have it, then a certain set of "simple" expressions just "do the obvious thing". Except that a / b still might call out-of-line into a 64bit or float emulation library, so personally I think although clear, that argument is fallacious. ;-)
Steve Jessop
I highly agree with this answer. One of the reasons I much prefer C++ over Java is because it *lets* you overload operators. It just allows for so much more flexibility in an OO environment. I'm not new to programming, and I'm not an idiot... I don't need my programming language holding my hand, and forcing me to code in a certain way. Typing out long function names *every single time* I want to do something is not my idea of "fun".
DoctorT
+3  A: 

Operator overloading was not a C++ invention - it came from Algol IIRC and even Gosling does not claim it is a bad idea in general.

Nemanja Trifunovic
Sure, but it was in its C++ incarnation that it gained a general air of disreputability.
skaffman
What do you mean by "general air of disreputability"? Most people I know use languages that support operator overloading (C++, C#) and I have never heard any complaints.
Nemanja Trifunovic
I'm speaking from my long-past experience with pre-ANSI C++, and I certainly recall a common dislike of them. Perhaps the situation improved with ANSI C++, or people just learned how not to abuse it.
skaffman
Speaking as someone that has been using C++ since cfront days (mid 80s) I can assure you that that the introduction of the ISO standard had no effect on people's prejudices regarding operator overloading.
anon
A: 

However, it wouldn't seem to be qualitatively different to the operator overloading in C++, where as I recall operators are defined as special functions.

AFAIK, There is nothing special in operator functions compared to "normal" member functions. Of course you only have a certain set of operators that you can overload, but that doesn't make them very special.

abababa22
+2  A: 

As the other answers have pointed out; operator overloading itself isn't necessarily bad. What is bad it when it is used in ways that make the resulting code un-obvious. Generally when using them you need to make them do the least surprising thing (having operator+ do division would cause trouble for a rational class's usage) or as Scott Meyers says:

Clients already know how types like int behave, so you should strive to have your types behave in the same way whenever reasonable... When in doubt, do as the ints do. (From Effective C++ 3rd Edition item 18)

Now some people have taken operator overloading to the extreme with things like boost::spirit. At this level you have no idea how it is implemented but it makes an interesting syntax to get what you want done. I'm not sure if this is good or bad. It seems nice, but I haven't used it.

Matt Price
I'm not arguing for or against operator overloading here, I'm not looking for people to justify them.
skaffman
Sprint doesn't come anywhere near the worst example I've come across - you should see what the RogueWave database library gets up to!
anon
I agree that Spirit misuses the operators, but I can't really think of a better way to do it.
Zifre
I don't think spirit is quite abusing the operators, but it's pushing it. I agree there's really no other way to do it. It basically creates a DSL within C++'s syntax. Very far off of what C++ was designed to do. Yes, there are far worse examples :) In general I use them where appropriate. Mostly just the streaming operators for easier debugging\logging. And even there it's just sugar that forwards to a method implemented in the class.
Matt Price
+98  A: 

C++ inherits true blue operators from C. By that I mean that the "+" in 6 + 4 is very special. You can't, for instance, get a pointer to that + function.

Scala on the other hand doesn't have operators in that way. It just has great flexibility in defining method names plus a bit of built in precedence for non-word symbols. So technically Scala doesn't have operator overloading.

Operator overloading isn't inherently bad, even in C++. The problem is when bad programmers abuse it. But frankly, I'm of the opinion that taking away programmers ability to abuse operator overloading doesn't put a drop in the bucket of fixing all the things that programmers can abuse. The real answer is mentoring. http://james-iry.blogspot.com/2009/03/operator-overloading-ad-absurdum.html

None-the-less, there are differences between C++'s operator overloading and Scala's flexible method naming which, IMHO, make Scala both less abusable and more abusable.

In C++ the only way to get in-fix notation is using operators. Otherwise you must use object.message(argument) or pointer->messsage(argument) or function(argument1, argument2). So if you want a certain DSLish style to your code then there's pressure to use operators.

In Scala you can get infix notation with any message send. "object message argument" is perfectly ok, which means you don't need to use non-word symbols just to get infix notation.

C++ operator overloading is limited to essentially the C operators. Combined with the limitation that only operators may be used infix that puts pressure on people to try to map a wide range of unrelated concepts onto a relatively few symbols like "+" and ">>"

Scala allows a huge range of valid non-word symbols as method names. For instance, I've got an embedded Prolog-ish DSL where you can write

female('jane)!  // jane is female
parent('jane,'john)!  // jane is john's parent
parent('jane, 'wendy)! // jane is wendy's parent

mother('Mother, 'Child) :- parent('Mother, 'Child) & female('Mother) // a mother of a child is the child's parent and is female

mother('X, 'john)?  // find john's mother
mother('jane, 'X)?  // find's all of jane's children

The :-, !, ?, and & symbols are defined as ordinary methods. In C++ only & would be valid so an attempt to map this DSL into C++ would require some symbols that already evoke very different concepts. Of course, this also opens up Scala to another kind of abuse. In Scala you can name a method $!&^% if you want to.

For other languages that, like Scala, are flexible in the use of non-word function and method names see Smalltalk where, like Scala, every "operator" is just another method and Haskell which allows the programmer to define precedence and fixity of flexibly named functions.

James Iry
A well-considered response. Thanks.
skaffman
very nice answer
anon
+1 - yes, very nicely put- Someone please mark this as the answer :)
Faisal Vali
Good answer James.
Erik Engbrecht
Joshua
you could for example do assert(female("jane")) in c++. That would not be confusing at all - nod back to the james-iry post about it not being that operator+ is a Bad Thing, but stupid programmers are.
pm100
@Joshua `int main() {return (3).operator+(5);}` results in `error: request for member ‘operator+’ in ‘3’, which is of non-class type ‘int’`
zildjohn01
+11  A: 

This article - "The Positive Legacy of C++ and Java" - answers your question directly.

"C++ has both stack allocation and heap allocation and you must overload your operators to handle all situations and not cause memory leaks. Difficult indeed. Java, however, has a single storage allocation mechanism and a garbage collector, which makes operator overloading trivial" ...

Java mistakenly (according to the author) omitted operator overloading because it was complicated in C++, but forgot why (or didn't realize that it didn't apply to Java).

Thankfully, higher level languages like Scala give developers options, while still running on the same JVM.

jmanning2k
Very interesting. Thanks for posting that.
skaffman
+1, I was going to say the same thing.
Bastien Léonard
Eckel is the only source I've ever seen for the idea that operator overloading was ditched from Java because of complications in C++ and he doesn't say what his source is. I would discount it.All the other sources I have say that it was ditched due to potential abuse. See http://www.gotw.ca/publications/c_family_interview.htm and http://www.newt.com/wohler/articles/james-gosling-ramblings-1.html. Just page search them for "operator overloading."
James Iry
+6  A: 

In general it is not a bad thing.
New languages such as C# also have operator overloading.

It is the abuse of operator overloading that is a bad thing.

But there are also problems with operator overloading as defined in C++. Because overloaded operators are just syntactic sugar for method calls they behave just like method. On the other hand normal built-in operators do not behave like methods. These inconsistency can be cause problems.

Off the top of my head operators || and &&.
The built in versions of these are short-cut operators. This is not true for overloaded versions and has caused some problems.

The fact that + - * / all return the same type that they operate on (after operator promotion)
The overloaded versions can return anything (This is where the abuse sets in, If your operators start to return some arbitrator type the user was not expecting things go down hill).

Martin York
A: 

I have never seen an article claiming that C++'s operator overloading is bad.

User-definable operators permit an easier higher level of expressivity and usability for users of the language.

Paul Nathan
+1  A: 

Other comments said it: it really doesn't. On the scala's side of things, though, type inference, strong types and the explicit use of implicit conversions make it a bit easier to use. But java is one of the few languages were symbols can't be methods: smalltalk and ruby makes great use of such methods, and it does not make any code harder to read. In fact, they are used with such ellegance in these languages that it actually makes it easier to read and write.

But no reason you can't make a mess out of it nonetheless. I'd usually keep symbols only to data structures, math types (numbers, rings, fields, groups, monois, matrixes, vector spcaces, categories, and so on) and value objects. In a DDD setting (assuming your domain is not math or logic), I'd keep them completely out of entities, repositories and services, allowing method's names to be part of the ubiquitous language.

Daniel Ribeiro
+2  A: 

I believe EVERY answer missed this. In C++ you can overload operators all you want, but you can't effect the precedence with which they're evaluated. Scala doesn't have this issue, IIRC.

As for it being a bad idea, besides precedence issues, people come up with really daft meanings for operators, and it rarely aids readability. Scala libraries are especially bad for this, goofy symbols that you must memorize each time, with library maintainers sticking their heads in the sand saying, 'you only need to learn it once'. Great, now I need to learn some 'clever' author's cryptic syntax * the number of libraries I care to use. It wouldn't be so bad if there existed a convention of ALWAYS supplying a literate version of the operators.

Saem
Scala has fixed operator precedence as well, doesn't it?
skaffman
I believe there is, but it's far flatter. More to the point, Scala has less operators period. +, -, * are methods, not operators, IIRC.Which is why 2 + 3 * 2, isn't 8, it's 10.
Saem
Scala has a precedence system based on the first character of the symbol.scala> 2 + 3 * 2res0: Int = 8
James Iry
+1  A: 

Operator overloading is not something that you really "need" very often, but when using Java, if you hit a point where you genuinely need it, it'll make you want to rip your fingernails out just so you have an excuse to stop typing.

That code which you've just found overflows a long? Yup, you're going to have to retype the whole lot to make it work with BigInteger. There is nothing more frustrating that having to reinvent the wheel just to change the type of a variable.

+2  A: 

The only thing known wrong in C++ is the lack of the ability to overload []= as a separate operator. This could be hard to implement in a C++ compiler for what is probably not an obvious reason but plenty worth it.

Joshua
+3  A: 

There is nothing wrong with operator overloading. In fact, there's something wrong with not having operator overloading for numeric types. (Take a look at some Java code that uses BigInteger and BigDecimal.)

C++ has a tradition of abusing the feature, though. An often-cited example is that the bitshift operators are overloaded to do I/O.

dan04