Coming from C++ to Java, the obvious unanswered question is why didn\'t Java include operator overloading?
Isn\'t Complex a, b, c; a = b + c;
much simpl
Assuming you wanted to overwrite the previous value of the object referred to by a
, then a member function would have to be invoked.
Complex a, b, c;
// ...
a = b.add(c);
In C++, this expression tells the compiler to create three (3) objects on the stack, perform addition, and copy the resultant value from the temporary object into the existing object a
.
However, in Java, operator=
doesn't perform value copy for reference types, and users can only create new reference types, not value types. So for a user-defined type named Complex
, assignment means to copy a reference to an existing value.
Consider instead:
b.set(1, 0); // initialize to real number '1'
a = b;
b.set(2, 0);
assert( !a.equals(b) ); // this assertion will fail
In C++, this copies the value, so the comparison will result not-equal. In Java, operator=
performs reference copy, so a
and b
are now referring to the same value. As a result, the comparison will produce 'equal', since the object will compare equal to itself.
The difference between copies and references only adds to the confusion of operator overloading. As @Sebastian mentioned, Java and C# both have to deal with value and reference equality separately -- operator+
would likely deal with values and objects, but operator=
is already implemented to deal with references.
In C++, you should only be dealing with one kind of comparison at a time, so it can be less confusing. For example, on Complex
, operator=
and operator==
are both working on values -- copying values and comparing values respectively.
This is not a good reason to disallow it but a practical one:
People do not always use it responsibly. Look at this example from the Python library scapy:
>>> IP()
<IP |>
>>> IP()/TCP()
<IP frag=0 proto=TCP |<TCP |>>
>>> Ether()/IP()/TCP()
<Ether type=0x800 |<IP frag=0 proto=TCP |<TCP |>>>
>>> IP()/TCP()/"GET / HTTP/1.0\r\n\r\n"
<IP frag=0 proto=TCP |<TCP |<Raw load='GET / HTTP/1.0\r\n\r\n' |>>>
>>> Ether()/IP()/IP()/UDP()
<Ether type=0x800 |<IP frag=0 proto=IP |<IP frag=0 proto=UDP |<UDP |>>>>
>>> IP(proto=55)/TCP()
<IP frag=0 proto=55 |<TCP |>>
Here is the explanation:
The / operator has been used as a composition operator between two layers. When doing so, the lower layer can have one or more of its defaults fields overloaded according to the upper layer. (You still can give the value you want). A string can be used as a raw layer.
I think this may have been a conscious design choice to force developers to create functions whose names clearly communicate their intentions. In C++ developers would overload operators with functionality that would often have no relation to the commonly accepted nature of the given operator, making it nearly impossible to determine what a piece of code does without looking at the definition of the operator.
Well you can really shoot yourself in the foot with operator overloading. It's like with pointers people make stupid mistakes with them and so it was decided to take the scissors away.
At least I think that's the reason. I'm on your side anyway. :)
Saying that operator overloading leads to logical errors of type that operator does not match the operation logic, it's like saying nothing. The same type of error will occur if function name is inappropriate for operation logic - so what's the solution: drop the ability of function usage!? This is a comical answer - "Inappropriate for operation logic", every parameter name, every class, function or whatever can be logicly inappropriate. I think that this option should be available in respectable programing language, and those that think that it's unsafe - hey no bothy says you have to use it. Lets take the C#. They drooped the pointers but hey - there is 'unsafe code' statement - program as you like on your own risk.