Is it a bad idea to overload &&, || or comma operator and Why?
I wouldn't overload operator&& or operator||. Even if you define a class that gives rise to a Boolean algebra (finite sets, for example), it would probably be a better choice to overload operator& and operator|.
The reason is that C++ programmers expect special semantics for operator&& and operator||: they are short-circuited, i.e. don't evaluate their right-hand argument if not necessary. You can't get this behavior by overloading, since you'll be defining a function.
Overloading operator, has been done in e.g. the Boost.Assign library. This is also the only example of its overloading that I know, and I've never even considered overloading it myself. You'd better have a very specific use case for it where no other operator is suited.
For overloading the logical operators in C++, the operands must be evaluated, which isn't the way things normally work with short circuiting of built-in types.
Look at the below link.
Don't overload logical operators in C++
You shouldn't overload any operators in a way that is surprising. :-)
If you can do it in a way that makes sense (not only to you), it is fine to do so.
Like others have said, the logical operators are special in that they have the effect of lazy evaluation. So your overloads should probably preserve this lazy effect, like with expression templates, or only be used where people don't expect this effect anyway.
It is usually a bad idea: those three operators have a sequencing effect which is lost when you overload them. Loosing that sequencing effect can cause arm (i.e. strange bugs) to those not expecting that lost.
There are cases with template expressions where you can keep the sequencing effect, in those cases I see no problem in overloading them.
The overloads of operator, I know of have another problem: they work in such a way that the apparent chains of operation isn't the real one. Usually, they are used in context when it makes no difference, but once in a blue moon, that is another source of a strange bugs.
I'd say it depends on what your overloads are doing. For example, && and || are expected to work as logical conditions, so if your overload semantics work somehow differently, they can confuse other people (or even yourself, if you don't use them for a while and forget what they do). Consider what you would expect the operators to do if you wouldn't know how they are overloaded and if it would be clearer to just use normal methods instead.
As the others have said, missing lazy evaluation is the main reason to avoid overloading logical operators.
However, there is one very good reason to overload them: Expression templates. The Boost.Lambda library does this, and it's very useful!
Its bad idea except situations when your classes represents some logic entity, because overloaded operators will disorientate and can cause new bugs in code.
Related
Why is it not possible to overload the ternary operator ' ?: '?
I use the ternary operator often to consolidate if statements, and am curious why the language designers chose to forbid this operator from being overloaded. I looked for an explanation as to why in C++ Operator Overloading but did not find one describing why this isn't possible. The only information the footnote provides is that it cannot be overloaded.
My initial guess is that overloading the operator will almost always violate number one or two of the principles given in the link above. The meaning of the overload will rarely be obvious or clear or it will deviate from its original known semantics.
So my question is more of why is this not possible rather than how, as I know it cannot be done.
if you could override the ternary operator, you would have to write something like this:
xxx operator ?: ( bool condition, xxx trueVal, xxx falseVal );
To call your override, the compiler would have to calculate the value of both trueVal and falseVal. That's not how the built-in ternary operator works - it only calculates one of those values, which is why you can write things like:
return p == NULL ? 23 : p->value;
without worrying about indirecting through a NULL pointer.
I think the main reason at the time that it didn't seem worth
the effort of inventing a new syntax just for that operator.
There is no token ?:, so you'd have to create a number of
special grammar rules just for it. (The current grammar rule
has operator followed by an operator, which is a single
token.)
As we've learned (from experience) to use operator overloading
more reasonably, it has become apparent that we really shouldn't
have allowed overloading of && and || either, for the
reasons other responses have pointed out, and probably not
operator comma as well (since the overloaded versions won't have
the sequence point which the user expects). So the motivation
to support it is even less than it was originally.
One of the principles of the ternary operator is that the true / false expression are only evaluated based on the truth or falseness of the conditional expression.
cond ? expr1 : expr2
In this example expr1 is only evaluated if cond is true while expr2 is only evaluated if cond is false. Keeping that in mind lets look at what a signature for ternary overloading would look like (using fixed types here instead of a template for simplicity)
Result operator?(const Result& left, const Result& right) {
...
}
This signature simply isn't legal because it violates the exact semantics I described. In order to call this method the language would have to evaluate both expr1 and expr2 hence they are no longer conditionally evaluated. In order to support ternary the operator would either need to
Take a lambda for each value so it could produce them on demand. This would necessarily complicate the calling code though because it would have to take into account lambda call semantics where no lambda was logically present
The ternary operator would need to return a value to denote whether the compiler should use expr1 or expr2
EDIT
Some may argue that the lack of short circuiting in this scenario is fine. The reason being that C++ already allows you to violate short circuiting in operator overloads with || and &&
Result operator&&(const Result& left, const Result& right) {
...
}
Though I still find this behavior baffling even for C++.
The short and accurate answer is simply "because that's what Bjarne decided."
Although the arguments about which operands should be evaluated and in what sequence give a technically accurate description of what happens, they do little (nothing, really) to explain why this particular operator can't be overloaded.
In particular, the same basic arguments would apply equally well to other operators such as operator && and operator||. In the built-in version of each of these operators, the left operand is evaluated, then if and only if that produces 1 for && or a 0 for ||, the right operand is evaluated. Likewise, the (built in) comma operator evaluates its left operand, then its right operand.
In an overloaded version of any of these operators, both operands are always evaluated (in an unspecified sequence). As such, they're essentially identical to an overloaded ternary operator in this respect. They all lose the same guarantees about what operands are evaluated and in what order.
As to why Bjarne made that decision: I can see a few possibilities. One is that although it's technically an operator, the ternary operator is devoted primarily to flow control, so overloading it would be more like overloading if or while than it is like overloading most other operators.
Another possibility would be that it would be syntactically ugly, requiring the parser to deal with something like operator?:, which requires defining ?: as a token, etc. -- all requiring fairly serious changes to the C grammar. At least in my view, this argument seems pretty weak, as C++ already requires a much more complex parser than C does, and this change would really be much smaller than many other changes that have been made.
Perhaps the strongest argument of all is simply that it didn't seem like it would accomplish much. Since it is devoted primarily to flow control, changing what it does for some types of operands is unlikely to accomplish anything very useful.
For the same reason why you really should not (although you can) overload && or || operators - doing so would disable short-circuiting on those operators (evaluating only the necessary part and not everything), which can lead to severe complications.
Previous answers focused on short-circuiting, which is somewhat valid but not even the real problem with trying to do this IMO.
The closest possible implementation of the existing ternary operator (without short circuiting) would have to look like this:
template<typename T0, typename T1>
std::variant<T0, T1>&& operator?:(bool predicate, T0&& arg0, T1&& arg1)
{
if(predicate)
return { std::forward<T0&&>(arg0) };
return { std::forward<T1&&>(arg1); }
}
However, T0 might be void. T1 might be void. This won't build in either of those cases.
The variant is necessary because T0 and T1 might not be implicitly convertible to one another and the return type can't be used for function overload resolution, and that was a C++17 library addition. But it still doesn't really work, because variant isn't implicitly convertible to any of its possible types.
I've started learning C++, so I don't know in my lack of knowledge/experience why something so seemingly simple to a rookie as what I'm about to describe isn't already in the STL. To add a vector to another vector you have to type this:
v1.insert(v1.end(), v2.begin(), v2.end());
I'm wondering whether in the real world people just overload the += operator to make this less verbose, for example to the effect of
template <typename T>
void operator+=(std::vector<T> &v1, const std::vector<T> &v2) {
v1.insert(v1.end(), v2.begin(), v2.end());
}
so then you can
v1 += v2;
I also have this set up for push_back to "+=" a single element to the end. Is there some reason these things should not be done or are specifically avoided by people who are proficient in C++?
This is actually a case where I would like to see this functionality in the form of an overload of append(). operator+= is kinda ambiguous, do you mean to add the elements of each vector to each other? Or you mean to append?
However, like I said, I would have welcomed: v1.append(v2); It is clear and simple, I don't know why it isn't there.
I think the main reason is that the semantics of += aren't obvious. There's the meaning that you have here, but there's also an equally valid meaning, which is element-wise addition of each element of equal-sized vectors. Due to this ambiguity I assume they decided it was better to rely on the user to call insert diretly.
Operators should be overloaded only when you are not changing the meaning of those operators.*
What that means is, for example, if there is no mathematical definition of the product of two objects, don't overload the multiplication operator for those objects. If there was a mathematical correspondence, operators overloading can make a class more convenient to use by allowing equations to be expressed in the form a*b + c rather than the more verbose (a.multiply(b)).add(c) Where addition and multiplication operators are used, addition and multiplication should be the intent. Any other meaning is more than likely to confuse others. Some other types where overloading operators is acceptable (and, in my opinion, preferable) are smart pointers, iterators, complex numbers, vectors, and bignums.
This follows from one of the design goals of C++, that it should be possible to define classes that are as easy to use as built in types. Of course there are operators you can define on classes which are not mathematical concepts either. You may wish to overload the == and != operators instead of writing an isEqual method, and might want to overload = because the compiler's default assignment operator is not what you want.
On the other hand, overloading an operator to do something unexpected, like defining ^ to translate a string to Japanese, is obscure and dangerous. Your fellow programmers will not be happy to find out that what looked like an exclusive or comparison was actually something very different. The solution then is to write your classes to make it easy to write clear and maintainable code, whether that means using operator overloading or avoiding it.
Adding two vectors is too ambiguous to warrent defining an operator. As others have shown, many people have different ideas of what this means, whereas for a string it is universally understood that adding two strings together means concatenation. In your example, it isn't entirely clear whether you want to do a component wise add on all the elements, add an element to the end, or concat two vectors together. Although it may be more concise to do it that way, using operator overloading to create your own programming language isn't the best way to go.
*Yes, I know Stroustrup overloaded << and >> to do stream operations rather than bitshifts. But those weren't used often compared to arithmetic and pointer operators in the first place, and it could be argued that now that everyone knows how to use cout, it's generally understood that << and >> are the inserter and extractor operators. (He originally tried to use just < and > for input and output, but the meaning of those operators was so ingrained in everyone's minds that the code was unreadable.)
In addition to what others mentioned about this syntax not being intuitive and therefore error prone, it also goes against a good design rule making general algorithms applied to various containers free functions, and container specific algorithms -- member functions. Most containers follow this rule, except std::string, which got a lot of flack from Herb Sutter for its monolithic design.
It is reasonable that sizeof and typeid cannot be overloaded, but I can't see the harm in overloading ?:, .* and .. Are there technical reasons for this?
To quote Bjarne Stroustrup:
There is no fundamental reason to
disallow overloading of ?:. I just
didn't see the need to introduce the
special case of overloading a ternary
operator. Note that a function
overloading expr1?expr2:expr3 would
not be able to guarantee that only one
of expr2 and expr3 was executed.
...
Operator . (dot) could in principle be
overloaded using the same technique as
used for ->. However, doing so can
lead to questions about whether an
operation is meant for the object
overloading . or an object referred to
by . ... This problem can be solved in
several ways. At the time of
standardization, it was not obvious
which way would be best.
Source
If you overload ., how would you access class members? What would be the meaning of obj.data?
What would the syntax be?
In fact, there are good reasons for not overloading any operator
which doesn't evaluate all of its operands: you shouldn't
overload && or || either (except in special cases). You can't
simulate this with an overloaded operator. Consider something
like:
p != NULL ? defaultValue : p->getValue()
where the type of defaultValue or p->getValue() causes overload
resolution to pick up your overload. It's a common idiom, but
it can't be made to work if you overloaded ?:.
Here's some reading material C++ FAQ Lite :)
In general there would be no benefit to overloading the operators above. What additional semantics would you be trying to implement?
The reason for overloading operators is to provide intuitive syntax to the user of your class. For example, it makes sense to overload + and += for strings. It's obvious to another developer what that means.
It's really not obvious what you would overload ?: for ... That said there are no technical reasons I am aware of that prevented these operators from being overloaded.
Overloading the -> operator allows for reference counted pointers to be created such as boost::shared_ptr. The concept of 'negating' an object might have different meanings in different contexts, so it's reasonable to occasionally overload this operator.
Defining "operator bool" is enough for ?: to work.
For operator . think of this: SomeClass."SomeString!!"
These overloadings prohibit compiler's lexer from parsing the file correctly.
The reason you can overload most operators is to be able to simulate built in types. Since none of the built in types can use the . operator, it wouldn't serve any purpose. operator* and operator-> are there so you can make your own pointer classes. All the math and boolean operators are there to be able to make your own numeric classes.
When overloading operators, is it necessary to overload >= <= and !=?
It seems like it would be smart for c++ to call !operator= for !=, !> for operator<= and !< for operator>=.
Is that the case, or is it necessary to overload every function?
Boost operators might be what you are looking for. These will derive most of your operators based on a few fundamental ones.
That C++ does not provide this automatically makes sense, as one could give totally different meanings to < and >, for example (although it would often be a bad idea).
I am going to take a minority viewpoint here. If you already use boost then using boost operators is not that big of a deal. It may be the correct and tested way to do things but adding boost dependency just for the operators is an overkill.
It is possible to write complex C++ programs without boost (which I personally find aesthetically unpleasant) and so to Keep It Simple (Stupid), to answer OP's question, if you overload operator ==, you should also overload operator !=. Same is true for <, >, ++ etc.
Yes, it is necessary, if you want all of them to work the way you want them to work.
C++ does not force any specific semantics on most of the overloadable operators. The only thing that is fixed is the general syntax for the operator (including being unary or binary and things like precedence and associativity). This immediately means that the actual functionality that you implement in your overload can be absolutely arbitrary. In general case there might not be any meaningful connection between what operator == does and what operator != does. Operator == might write data to a file, while operator != might sort an array.
While overloading operators in such an arbitrary fashion is certainly not a good programming practice, the C++ language cannot assume anything. So, no, it cannot and will not automatically use ! == combination in place of !=, or ! > combination in place of <=.
No, you only need to overload operator == and operator <, the standard library will take care of the rest :)
(EDIT: see using namespace std::rel_ops ;)
Yes it is necessary to overload whichever operators you want to be used as you define them - C++ will not make the decision you describe above; however, keep in mind that if the reason you are overloading is to sort your class, than you only need to override the operators used by the sort routine. In the case of the RTL sort algorithm you only need to override < and =.
Yes! They are each technically different operators. C++ compilers are not inherently inference engines, they are parsers/compilers. They will only do as much as you say to do.
http://www.parashift.com/c++-faq-lite/operator-overloading.html, http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B
There are a few shortcuts you can use, such as CRTP to get them automatically injected (see the various Compare classes) into your class.
C++ does not, as a language, define any operator in terms of any other overloaded operator. Just because you have operator+, doesn't mean you get operator+= for free (unlike Ruby and Scala). Just because you have operator < and == doesn't mean you get <= for free. Just because you have operator == doesn't mean you get != for free (unlike Ruby and Scala). Just because you have unary operator * (unary) doesn't mean you get operator -> for free.
std::relops (if imported correctly) and provide default definitions, and Boost provides some mix-ins that define all of the comparison operators in terms of < and ==.
You can use overloading to use user defined names.
Operator overloading means using the same operator to do perform operation on different items which are not in that category. Function overloading means using the same name of function but different arguments, so as to overcome the overhead when the same function is called during looping.
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 1 year ago.
Improve this question
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++?
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.
Whatever you want to call it, 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.
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.
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.
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.
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.
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.
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).
Guy Steele argued that operator overloading should be in Java as well, in his keynote speech "Growing a language" - there's a video and a transcription of it, and it's really an amazing speech. You will wonder what he is talking about for the first couple of pages, but if you keep on reading, you will see the point and achieve enlightenment. And the very fact that he could do such a speech at all is also amazing.
At the same time, this talk inspired a lot of fundamental research, probably including Scala - it's one of those papers that everybody should read to work in the field.
Back to the point, his examples are mostly about numeric classes (like BigInteger, and some weirder stuff), but that's not essential.
It is true, though, that misuse of operator overloading can lead to terrible results, and that even proper uses can complicate matters, if you try to read code without studying a bit the libraries it uses. But is that a good idea? OTOH, shouldn't such libraries try to include an operator cheat sheet for their operators?
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.
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.
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.
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.
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.
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.