0

Recently, I've been learning a bit more of C++ and the dangers and uses of operator overloading, and the readability boost it provides to arithmetic types (like Complex numbers).

A while ago, I was playing around with Rust, and I really liked how they handled operator overloading, that is, via Traits in the std::ops crate. So, having:

struct Fraction {
  numerator: i32,
  denominator: i32,
}

impl Add for Fraction { /* ... */ }

Ends up overloading the + operator. This leads me to wonder the subject of the title...

Can Java implement a limited set of operator overloading via Interfaces? The compiler could check if the caller class implements the interface for a given operator, and change the operator to a method call (thus, it all being syntax sugar) or fail compiling otherwise.

Would this imply breaking changes for code compiled in older versions? Anyone know if this has been already discussed in mailings list, or a JEP proposed?

2
  • 2
    You could preserve backwards compatibility by compiling operators to functions. That's all an operator really is anyway: a function. I don't think it would even have to be limited, nor would you necessarily need interfaces. May 19 '16 at 17:08
  • this is why parenthesis-free (well mostly) languages with infix functions (like haskell) are such a joy! + is simply a function of type Num a => a -> a -> a (static int +(int a, int b) in C-like syntax (although in haskell it's polymorphic))
    – sara
    May 19 '16 at 20:20
7

The answer to your question is rather simple: Backwards-compatibility means not changing the meaning of existing code. Since there is no existing code using user-defined operators, because user-defined operators do not exist, introducing them cannot possibly break backwards-compatibility.

Foo a = new Foo();
Foo b = new Foo();

Foo c = a + b;

Such code just can't be written today.

The simplest implementation of operator overloading would be to just make them methods. E.g.

class Fraction {
  int numerator, denominator;

  public Fraction *(Fraction other) {
    return new Fraction(numerator * other.numerator, denominator * other.denominator);
  }
}

Since those names are currently illegal, backwards-compatibility is preserved: there is no code currently which uses these names and whose meaning could change. If you implement a name-mangling scheme for those methods, you could even get by without changing the bytecode and classfile formats, so code that is compiled with a JavaXYZ compiler will still run on Java 8.

This is the simplest possible solution. If you want something more sophisticated, like defining the fixity, associativity and precedence of operators, you will have to do more work. In particular, parsing is (somewhat) complicated: you have to know whether is left-associatice or right-associative before you can parse a ∪ b ∪ c correctly, for example. So you have to analyze the imported operator definitions before you can parse the code.

7
  • 1
    "Make them methods" is how scala does custom operators
    – Daenyth
    May 19 '16 at 19:33
  • Well, actually, Scala's approach is even simpler: there are no operators. foo bar baz is simply an alternative way of writing foo.bar(baz). (This is only half-true: there is some support for operators in that for method names composed purely of operator characters, when called using operator notation, the first character of the method determines the precedence. Also, when the last character is :, the call is interpreted to be right-associative.) May 19 '16 at 19:41
  • Ruby would be a better comparison: Ruby has a fixed set of operators, with fixed precedence, fixity and associativity, and those operators can be implemented by defining methods with corresponding names (usually identical to the operator, except +@ and -@ for unary + and -). May 19 '16 at 19:43
  • I'm not sure definable fixity makes sense in an OO language.. What should class A { public A operator+ (A a) { ... } left 5}; class B extends A { public A operator+ (A a) { ... } right 7 }; ... A a1 = new A(), a2 = new B(), a3 = new B(), a4 = a1 + a2 + a3; do?
    – Jules
    May 19 '16 at 23:03
  • @Jules: Hopefully fail to compile :-D May 19 '16 at 23:28
1

It would break existing code if you could override == comparison, or even = assignment. == is used to compare the memory addresses of two objects, independent of what their equals() method says. == is even true for two null objects. I don’t want to imagine what happens if objects are allowed to override = assignment operator.

1
  • 2
    Allowing some operators to be overloaded does not necessarily mean allowing all operators to be overloaded. Most languages that do allow operator overloading do not allow assignment to be overloaded (e.g. Python, Ruby, Smalltalk, Scala, Haskell). C++ does allow to overload assignment, and so far it hasn't brought down the Apocalypse. The behavior of == in Java breaks OO in a deeply fundamental way, being able to override it to fix that would be a good thing IMO. May 20 '16 at 9:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.