views:

298

answers:

6

Java forbids operator overloading, but coming from C++ I do not see any reason for that. In languages where operator symbols are symbols as any other, same rules apply to "+" as to"plus" and there is no problem. So what is the point?

Edit: To be more concrete, show me which disadvantage overloaded "+" may have over overloaded "equals".

A: 

The point is that whenever you see, for example, a plus sign being used in the code, you know exactly what it does given that you know the types of its operands (which you always do in Java, as it is strongly typed).

danben
C++ is strongly typed as well, and *given the types of the operands* you certainly do know—or can find out—what the operator does in context.
Jon Purdy
@Jon Purdy: You are of course correct but you missed the point of my answer. It is not about the language being strongly typed, but knowing the effects of the operator vs. having to find out (in particular, the cases where you think you know but actually have yet to find out).
danben
@danben have you ever used any API without reading the source code for implementation beforehand? How are operator symbols different?
Gabriel Ščerbák
Is that a serious question? Of course I have used APIs without reading their source code. That is the point of a well-designed API.
danben
@Gab I don't know about you, but I often only read what I think I need to know (e.g. I don't read every the docs for every single method, just ones I think I'll need to use) and I wouldn't normally think to look for overloaded operators. I'm not disagreeing with overloading operators, I primarily use C# and I love it when they're used properly, I'm just disagreeing with the argument of reading all the docs before using something.
Davy8
What are you guys implying, overloaded operators are some kind of esoteric beings? They are just methods. If you have two `Complex` objects, obviously you know what `+` will do on them. If you have a `Bob` and `Jim` object, you aren't going to be an idiot and just add them, you aren't even going to _care_ what the `+` method does unless it has meaning to you, in which case you will read the javadoc...
Longpoke
@danben it was rhetorical to make you think, but I have not expressed myself fully enough. Of course you use APIs without knowing (everything) about implementation. But how do you do know what the e.g. function does? I would sayd it is because of the context and name. My point is that once you have "*" (multiplication) for matrices, you know what it does by name and context, it is same as if it would be named "multiply".
Gabriel Ščerbák
@Davy8 you misunderstood, I am not advocating for reading more than needed. look at my previous comment to danben. You argue that operators can be misused, but how is it different from badly named APIs? How is "compare", "equals" and "same" better from e.g. "=", "==", "===" (the order and names have been changed to not resemble any real language constructs:)...)?
Gabriel Ščerbák
@Longpoke exactly what I ment:)
Gabriel Ščerbák
+7  A: 

Just as many other things in Java, this is a restriction because it may be confusing if used improperly. (Similarly as pointer arithmetic is forbidden because it is error prone.) I'm a big fan of Java, but I'm generally of the opinion that it shouldn't be forbidden just because it could be misused.

For instance, BigInteger would benefit greatly from overloading the + operator.

aioobe
Pointer arithmetic is problematic, because it is IMHO on lower level of abstraction and is strongly architecture dependant.I personally never heard of errors because of operator overloading. In math, operators are used differently depending on the context, why in programming we want special language constructs for arithmetic, which works only in special cases?
Gabriel Ščerbák
+1  A: 

There is no problem with operator overloading itself, but how it's actually has been used. As long as you overload the operators to make sense, the language still makes sense, but if you give other meanings to operators, it makes the language inconsistent.

(One example is how the shift left (<<) and shift right (>>) operators has been overloaded in C++ to mean "input" and "output"...)

So, the reasoning when leaving out operator overloading was probably that the risk of misuse was greater than the benefits of having operator overloading.

Guffa
If we use strongly typed languages and are quite explicit about the types, why not to make API more pleasant? I like << and >> stream operators very much and I saw also << in Ruby for insertion into arrays. It all feels and seems right and it is used easily.
Gabriel Ščerbák
@Gabriel: In Ruby `<<` is a method that is built in from the start, so it's not an example of operator overloading changing meaning of operators. The stream operators in C++ works well only because they are an exception. If you start inventing new meanings for operators to all your classes, the code will quickly get unmanagable.
Guffa
@Guffa AFAIK Ruby AFAIK does not use operators, everything is a message, so the methods can be overloaded, this holds for "<<" as well as for "=" (attr_accessor adds method fo asigning values to attributes). Another Ruby example would be e.g. arithmetic for Time. I agree that operator overloading can be misused, but I think same holds for any method name. For examples look at my comment to Davy8.
Gabriel Ščerbák
@Gabriel: Yes, you can create bad method names, but that can't create even close to the mess that you can cause with bad operators as it doesn't changes the meaning of the syntax. If you for example overload the `+` operator to do subtraction in one class, and multiplication in another, `x + y` and `y + x` would have totally different meanings...
Guffa
@Guffa ok, how is it different from overloading "plus" method in the same way? Is the "." notation what really bothers you? Or even the infixness of many operators? Does not "equals" have the same problem? I cannot really see the difference.
Gabriel Ščerbák
+1  A: 

I think that Java would benefit greatly from extending its operators to cover built-in Number object types. Early (pre-1.0) versions of Java were said to have it (in that there were no primitives - everything was an object) but the VM technology of the time made it prohibitive from a performance view.

But in terms of in general allowing user defined operator overloading, it is not in the spirit of the Java language. The main problem is simply that it is hard to implement an operator that is consistent with what you expect from mathematics across object types and it will open the door to a lot of bad implementations which lead to a lot of hard to find (therefore expensive) bugs. You can just look at how many bad equals implementations (as in violate the contract) there are in general Java code, and the problem would only get worse from there.

Of course there are languages that prioritize power and syntactical beauty over such concerns, and more power to them. It is just not Java.

Edit: How is a custom + operator different than a custom == implementation (captured in Java in the equals(Object) method)? It isn't, really. It is just that by allowing operator overloading, things that are intuitive to a sixth grader become untrue. The real world experience of equals(Object) implementations shows how such complex contracts become hard to enforce in the real world.

Further Edit: Let me clarify the above, as I shortened it while editing and lost the point. A + operator in math has certain properties, one of which is that it doesn't matter which order the numbers on either side appear - it has the same result. So consider even the simplest case of a + performing an add to a Collection:

  Collection a = ...
  Collection b = ...
  a + b;
  System.out.println(a);
  System.out.println(b);

The intuitive understanding of + would lead to an expectation that a + b or b + a would give the same result, but of course they would not. Start mixing two object types that take each other as paramaters in their plus method (say Collection and String) and things get harder to follow.

Now certainly it is possible to design operators on objects which are well understood and lead to better, more readable and more understandable code than without them. But the point is that more often than not in home-grown corporate APIs what you would end up seeing is obfuscated code.

Yishai
Exactly what you say, just explain me how are custom equals different from custom plus. I think it would a better compromise if operators could be overloaded except for the primitive types and their object equivalents. The thing with the contract is, that most language support only name and structure contracts, if Java supported contracts better, it would make programming far more easier.
Gabriel Ščerbák
2 Edit Before you teach a pupil what "+" means, she/he knows as intuitively what "add" means. Look at how "%" (modulo) behaves, you might say it is intuitive what it does, however, often the implementation in different languages is different from the algebraic definition of remainder of integral division. If operator overloading was allowed, it could be adjusted to work as expected in certain contexts.
Gabriel Ščerbák
+4  A: 

OK, I'll try my hand at this under the assumption that Gabriel Ščerbák is doing this for better reasons than railing against a language.

The issue for me is one of manageable complexity: How much of the code in front of me do I have to decode vs. simply read?

In most conventional languages, upon seeing the expression a + b I know what is going to happen. The variables a and b will be added together. I'm pretty confident that behind the scenes the code will be very concise, very fast native machine code that adds the two numbers, whether the numbers are short integers or double-precision or some mixture of the two. (In some languages I may have to also assume that these could be strings being concatenated, but that's a rant for an entirely different question -- but one that flavours this rant if you peer at it from the right angle.)

When I make my own user-defined type -- say the omnipresent Complex type (and why Complex isn't a standard data type in modern languages is way the Hell beyond me, but that, again, is a rant for a different question) -- if I overload an operator (or, rather, if the operator is overloaded for me -- I'm using a library, say), short of peering very closely at the code I will not know that I'm now calling (possibly-virtual) methods on objects instead of having very tight, concise code generated for me behind the scenes. I will not know of the hidden conversions, the hidden temporary variables, the ... well, everything that goes along with writing many operators. To find out what's really going on in my code I have to pay very close attention to every line and keep track of declarations that may be three screens away from my current location in the code. To say that this impedes my understanding of the code flowing before my eyes is an understatement. Important details are being lost because the syntactic sugar is making things taste too tasty.

When I'm forced to use explicit methods on the objects (or even static methods or global methods where that applies) this is a signal to me, while I'm reading, that tells me of the potential cost overheads and bottlenecks and the like. I know, without even having to think for an instant, that I'm dealing with a method, that I've got dispatching overhead, that I may have temporary object creation and deletion overhead, etc. Everything's in front of me right before my eyes -- or at least enough indicators are in front of me that I know to be more careful.

I'm not intrinsically opposed to operator overloading. There are times when it makes code clearer, yes indeed, especially when you have complicated calculations over many baffling expressions. I can understand, however, exactly why someone might not want to put that into their language.

There is a further reason not to like operator overloading from the language designer's viewpoint. Operator overloading makes for very, very, very difficult grammars. C++ is already infamous for being nigh-unparseable and some of its constructs, like operator overloading, are the cause of it. Again from the viewpoint of someone writing the language I can fully understand why operator overloading was left off as a bad idea (or a good idea that's bad in implementation).

(This is all, of course, in addition to the other reasons you've already rejected. I'll submit my own overloading of operator-,() in my old C++ days in that stew just to be really annoying.)

JUST MY correct OPINION
+1  A: 

There are a few problems:

  • Overloading logical operators has side effects because of lazy evaluation.
  • Even in mathematical types there are ambiguities, is (3dpoint*3dpoint) a cross or scaler product
  • You can't define new operators, so people reuse existing operators in novel ways eg. "string1%string2" to mean split string1 on string2.

But you can't always protect idiots from themselves even with an outright ban.

Martin Beckett