operator overloading

P

Patricia Shanahan

Wojtek said:
Arne Vajhøj wrote :

Which is my point.

Maybe this subthread suggests a solution. Define, for example, an
interface Addable<T> with

T additionOperation(T o);

as its only method.

If BigInteger implemented Addable<BigInteger> the compiler would replace
a+b for BigInteger a and b with a.additionOperation(b).

This is similar to the idea of allowing special for-loop syntax for
iteration over the elements of an Iterable Object.

The hope is that having to call the method "additionOperation" will make
people think twice about using it for anything other than addition.

Of course, one could go on to define Subtractable, Multipliable, and
Dividable. If the decision were made to allow [] indexing, there would
be an interface Indexable with methods get() and set(). Perhaps
there should also be an interface LongIndexable, with get and set
methods that use longs instead of ints.

Patricia
 
T

Tom Anderson

Maybe this subthread suggests a solution. Define, for example, an
interface Addable<T> with

T additionOperation(T o);

as its only method.

Analogising to multiplication, this is going to make it impossible to
write my Matrix class which can be multiplied any of a double, a Vector,
or another Matrix, because you can't implement multiple instances of a
generic interface. Well, you could, but you'd have to do an instanceof
switch inside additionOperation, or implement some kind of ugly bounce
dispatch.

Anyway, i'm not happy with this solution, although i appreciate and
strongly agree with its intent.

tom
 
A

Andreas Leitgeb

Patricia Shanahan said:
Maybe this subthread suggests a solution. Define, for example, an
interface Addable<T> with
T additionOperation(T o);
as its only method.

This would prevent "overloading".
e.g. a BigInteger should also be addable to a primitive int, long, ...

And with that comes the problem of how to add two different types
where the first one's addition-method doesn't know the second summand's
type, but the second one's knows the first. And this even for
non-commutative operations like subtraction,division,etc.

I think there is some more overhead necessary.

I also think it's worth it in the end.
 
P

Patricia Shanahan

Tom said:
Analogising to multiplication, this is going to make it impossible to
write my Matrix class which can be multiplied any of a double, a Vector,
or another Matrix, because you can't implement multiple instances of a
generic interface. Well, you could, but you'd have to do an instanceof
switch inside additionOperation, or implement some kind of ugly bounce
dispatch.

Anyway, i'm not happy with this solution, although i appreciate and
strongly agree with its intent.

Good point. How about this modification?

Addable, Multipliable, etc. become marker interfaces. Suppose a is a
reference to Multipliable or a type implementing Multipliable. Then the
compiler would process a+b as though it were a.multiplicationOperation(b).

You would make your Matrix class implement Multipliable, and provide
overloaded multiplicationOperation methods for formal parameter types
double, Vector, and Matrix.

Patricia
 
W

Wojtek

Patricia Shanahan wrote :
Addable, Multipliable, etc. become marker interfaces. Suppose a is a
reference to Multipliable or a type implementing Multipliable. Then the
compiler would process a+b as though it were a.multiplicationOperation(b).

I really like this. It merges operator overloading with a very strong
suggestion that this is only a mathematical operation.

So to pervert this by making the plus sign do something bizzare would
take a really large ego.

Um, though a+b should be a*b

:)
 
P

Patricia Shanahan

Wojtek said:
Patricia Shanahan wrote :

I really like this. It merges operator overloading with a very strong
suggestion that this is only a mathematical operation.

So to pervert this by making the plus sign do something bizzare would
take a really large ego.

Um, though a+b should be a*b

:)

That's what comes of switching examples from addition to multiplication
without sufficient proof reading. :-(

We could deal with e.g. double * Matrix by allowing declaration of a
method rhsMultiplationOperator.

For a*b, if a is not Multipliable or there is no applicable, accessible
method for a.multiplicationOperator(b) then check b. If b is
Multipliable, treat a*b as b.rhsMultiplicationOperator(a).

For a commutative operation, that might be implemented as:

Matrix rhsMultiplicationOperator(double left){
return multiplicationOperator(left);
}

I don't really like the method name. Suggestions?

Patricia
 
T

Tom Anderson

Good point. How about this modification?

Addable, Multipliable, etc. become marker interfaces. Suppose a is a
reference to Multipliable or a type implementing Multipliable. Then the
compiler would process a+b as though it were
a.multiplicationOperation(b).

I'm happy with this. What you describe is exactly how it works in python
or C++, with a slightly different method name, and requiring a marker
interface. Could we even drop the marker interface? What do we gain by
having it?

If you're talking about handling this as a rewrite rule, then the type of
the receiver variable would have to have a suitable multiplication method.
You couldn't multiply a plain Multipliable, but overloading would work.
That's fine by me.

The alternative to doing it by rewriting would be to do a fully dynamic
invocation, but that's clearly madness, and doesn't preserve type safety,
eg:

Multipliable m = new Matrix(23, 17) ;
Object result = m * new GaloisField(7).getElement(5) ; // O NOES!

tom
 
T

Tom Anderson

We could deal with e.g. double * Matrix by allowing declaration of a
method rhsMultiplationOperator.

For a*b, if a is not Multipliable or there is no applicable, accessible
method for a.multiplicationOperator(b) then check b. If b is
Multipliable, treat a*b as b.rhsMultiplicationOperator(a).

For a commutative operation, that might be implemented as:

Matrix rhsMultiplicationOperator(double left){
return multiplicationOperator(left);
}

I don't really like the method name. Suggestions?

rotarepOnoitacilpitlum()?

I quite like that it starts with 'rotare', which sounds like a latin verb
for rotating something.

FWIW, python calls this __rmul__, where normal multiplication is __mul__.

I'd suggest multiply and rightMultiply as the names.

tom
 
D

Daniel Pitts

Wojtek said:
Patricia Shanahan wrote :

I really like this. It merges operator overloading with a very strong
suggestion that this is only a mathematical operation.

So to pervert this by making the plus sign do something bizzare would
take a really large ego.

Um, though a+b should be a*b

:)
What about @Annotations instead?

public class Foo {

@AdditionOperation
Foo anyMethodIWant(Foo foo) {...}

@AdditionOperation
Foo addInteger(int foo) {...}

@MultiplicationOperation
Bar multiplyFooIntoBar(Foo foo) {...}
}

foo*foo would then become foo.muliplyFooIntoBar(foo), and foo+3 becomes
foo.addInteger(3); where foo+anotherFoo becomes
foo.anyMethodIWant(anotherFoo);

Problems may arise with commutative vs non-commutative operations...
Hmm, now that I think about it. having operators be instance methods
doesn't necessarily work... It might be that we would need to use static
imports in combination with annotations for it to work well.
 
P

Patricia Shanahan

Daniel said:
What about @Annotations instead?

public class Foo {

@AdditionOperation
Foo anyMethodIWant(Foo foo) {...}

This loses the property that I think may make this relatively
non-controversial, the requirement that the method be declared to be
additionOperation. The people who dislike operator overloading seem to
believe that programmers are more likely to declare a "+" operation that
has nothing to do with addition than an addition method that has nothing
to do with addition.

Patricia
 
P

Patricia Shanahan

Tom said:
I'm happy with this. What you describe is exactly how it works in python
or C++, with a slightly different method name, and requiring a marker
interface. Could we even drop the marker interface? What do we gain by
having it?
....

The marker interface avoids any backwards compatibility problems with a
method called "additionOperation" that is not intended to be used to
implement "+".

Patricia
 
P

Patricia Shanahan

Tom said:
rotarepOnoitacilpitlum()?

I quite like that it starts with 'rotare', which sounds like a latin
verb for rotating something.

FWIW, python calls this __rmul__, where normal multiplication is __mul__.

I'd suggest multiply and rightMultiply as the names.

The issue with simple names such as "multiply" is classes such as
BigDecimal that already use them, but should implement Multipliable.
Would it be good or bad to automatically turn those methods into
operator implementations?

Patricia
 
M

Mark Space

Patricia said:
This loses the property that I think may make this relatively
non-controversial, the requirement that the method be declared to be

From my personal perspective, you've already lost that, because an
interface can be added to any class. That's rather more abusable than
I'd prefer.

One root class, abstract or otherwise, is less abusable, in my opinion.

public abstract class AbstractNumber {

public abstract AbstractNumber multiply( AbstractNumber n );
public abstract AbstractNumber divide( AbstractNumber n );
// etc.

}

Now you can still abuse this and derive things from AbstractNumber that
really aren't abstract numbers, but that can't be helped. What you
can't do is something like:

class MyList extends AbstractList implements Addable {

// abuse city

}

So by using one root class, operator overloading can't be add willy
nilly to any class. It's confined to descendants of AbstractNumber (and
maybe something like AbstractMatrix).

I know those of you still debating this don't really agree with that,
I'm just waving my little not-so-much-operator-overloading flag around,
just to show it's still here. :)
 
P

Patricia Shanahan

Tom Anderson wrote:
....
If you're talking about handling this as a rewrite rule, then the type
of the receiver variable would have to have a suitable multiplication
method. You couldn't multiply a plain Multipliable, but overloading
would work. That's fine by me.

The alternative to doing it by rewriting would be to do a fully dynamic
invocation, but that's clearly madness, and doesn't preserve type
safety, eg:

Multipliable m = new Matrix(23, 17) ;
Object result = m * new GaloisField(7).getElement(5) ; // O NOES!

My intention is that the compiler would apply the normal method
invocation rules after rewriting a*b to a.multiplyOperation(b). That
allows for overloading and inheritance, but in a way that is already
familiar. I don't think Matrix would declare or inherit a
multiplyOperation method that takes a GaloisField element parameter.

Patricia
 
P

Patricia Shanahan

Mark said:
From my personal perspective, you've already lost that, because an
interface can be added to any class. That's rather more abusable than
I'd prefer.

Stress *relatively* non-controversial.
One root class, abstract or otherwise, is less abusable, in my opinion.

public abstract class AbstractNumber {

public abstract AbstractNumber multiply( AbstractNumber n );
public abstract AbstractNumber divide( AbstractNumber n );
// etc.

}
....

How would you relate AbstractNumber to the existing java.lang.Number?
Would AbstractNumber be a superclass or subclass of Number?

Patricia
 
M

Mark Space

Patricia said:
Stress *relatively* non-controversial.

No worries.

How would you relate AbstractNumber to the existing java.lang.Number?
Would AbstractNumber be a superclass or subclass of Number?

Well, I haven't thought about this carefully, so I'm not sure of all the
ramification. So I don't think I feel comfortable at this time
proposing changing the hierarchy of existing classes.

Sun seems close to modifying their compiler for Java 7 to perform some
magic on the BigInteger and BigDecimal classes to allow infix operators
for * + - / and % (I think % too). That's good enough for me.

What I think I'd propose is to add a new class which inherits from
java.lang.Number, called AbstractNumber, and let folks who want to do
their own operator overloading make new classes descended from that class.

This way absolutely nothing changes, except for one new class that gets
added. Byte, Integer, Double, etc. get a new sibling class,
AbstractNumber, and that's it. Except that AbstractNumber is also
special, like BigInteger and BigDecimal, and the compiler will also do
some magic on it's descendants to allow the proposed 5 infix operators.

And we might add AbstractMatrix descended from AbstractNumber for []
too, but that appears to be a tad more controversial. It would however,
make the semantic of using [] distinct from any use of [] on Collections.

Just my 2 pennies.
 
D

Daniel Pitts

Mark said:
Patricia said:
Stress *relatively* non-controversial.

No worries.

How would you relate AbstractNumber to the existing java.lang.Number?
Would AbstractNumber be a superclass or subclass of Number?

Well, I haven't thought about this carefully, so I'm not sure of all the
ramification. So I don't think I feel comfortable at this time
proposing changing the hierarchy of existing classes.

Sun seems close to modifying their compiler for Java 7 to perform some
magic on the BigInteger and BigDecimal classes to allow infix operators
for * + - / and % (I think % too). That's good enough for me.

What I think I'd propose is to add a new class which inherits from
java.lang.Number, called AbstractNumber, and let folks who want to do
their own operator overloading make new classes descended from that class.

This way absolutely nothing changes, except for one new class that gets
added. Byte, Integer, Double, etc. get a new sibling class,
AbstractNumber, and that's it. Except that AbstractNumber is also
special, like BigInteger and BigDecimal, and the compiler will also do
some magic on it's descendants to allow the proposed 5 infix operators.

And we might add AbstractMatrix descended from AbstractNumber for []
too, but that appears to be a tad more controversial. It would however,
make the semantic of using [] distinct from any use of [] on Collections.

Just my 2 pennies.
Sure, but that doesn't work well with Complex numbers or other
fields/rings/groups that aren't real-numbers.
It also doesn't work well with things that yield different types than
themselves for these operators. (vector multiplication for instance)
 
P

Patricia Shanahan

Mark Space wrote:
....
What I think I'd propose is to add a new class which inherits from
java.lang.Number, called AbstractNumber, and let folks who want to do
their own operator overloading make new classes descended from that class.
....

That would force concrete classes inheriting from AbstractNumber to
provide all the methods in Number. What is the doubleValue() of a
matrix?

Patricia
 
M

Mark Space

Patricia said:
Mark Space wrote:
...
...

That would force concrete classes inheriting from AbstractNumber to
provide all the methods in Number. What is the doubleValue() of a
matrix?


A good point. Do you think it would be better to derive AbstractNumber
directly from Object?

However, here's a guess how doubleValue() might be implemented for a matrix:

All of the methods in java.lang.Number are identities. The
doubleValue() of a Byte with a value of 1 is still 1, insofar as a
double is able to represent the value of 1.

To me, this means that an Matrix which is implemented with, say, floats,
should return a Matrix implemented with doubles when doubleValue() is
called on it. Not all of these conversions make sense to me. I don't
see the point of a Matrix which is created with byteValue(), for example.

So I guess AbstractNumber could attempt to hide the conversion methods
something like this:

abstract public AbstractNumber doubleValue();

But I don't think this is even a legal syntax, let alone good idea. (I'm
not even going to recheck the JLS for syntax.) Because regardless, it
could give the compiler fits trying to pick out the correct method.

So maybe just deriving AbstractNumber from Object, and re-implementing
the conversion methods with a correct signature, is the better idea.
That's a bummer, because I really wanted to add the new as sib of the
other Number classes -- it would show up at the right spot in the Java
doc automagically. But I guess one more "see also" in the Java doc
won't kill anybody.
 
M

Mark Space

Daniel said:
Sure, but that doesn't work well with Complex numbers or other
fields/rings/groups that aren't real-numbers.
It also doesn't work well with things that yield different types than
themselves for these operators. (vector multiplication for instance)

How so?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top