Re: operator overloading
This message is in MIME format. The first part should be readable text,
while the remaining parts are likely unreadable without MIME-aware tools.
---910079544-895386277-1210291270=:10697
Content-Type: TEXT/PLAIN; CHARSET=iso-8859-1; FORMAT=flowed
Content-Transfer-Encoding: 8BIT
Content-ID: <Pine.LNX.4.64.0805090101241.17330@urchin.earth.li>
On Thu, 8 May 2008, Owen Jacobson wrote:
On May 8, 1:52?pm, Tom Anderson <t...@urchin.earth.li> wrote:
You need to be able to have things which you can, say, add and multiply,
but not divide - anything a mathematician would call a ring, like a
three-by-three matrix. Forcing these to have divide methods that just
threw an exception would be pretty poor.
You could even model a little hierarchy on discrete mathematics: Addable,
Multipliable, Ring extends Addable, Multipliable, Dividable, Field extends
Ring, Dividable, etc.
The question is, at the language and standard library level, do you
provide four interfaces (for +, *, /, and -) or one (for all four) or
five (both) or some other combination? If you provide an interface for
each operator, obviously applications can define their own composite
interfaces, but there may be places where the standard library uses
multiple operators on a single type, so there might end up being some
"standard" composite interfaces while other combinations of operators
are unrepresented.
Are there really things which can be added and divided but not multiplied?
How often will it be a problem that there isn't an interface for this?
If you include every possible combination of operators in the standard
library, you end up with a huge number of mostly-useless interfaces.
Which is a pretty fair description of the standard library at present!
(And that doesn't even get into operators like ++ and +=; I'd probably
prefer to have +=, at least, implemented automatically in terms of +
instead of being its own operator, but it's not a clear choice.)
There are times when being able to override += would be useful, because
using + to synthesise it involves throwing away an object, and if they're
heavyweight, that's not great. If your objects are million-by-million
matrices, for instance, you'd really like to be able to add in place.
One thing we definitely shouldn't have is overriding of the = operator,
as C++ lets you do. That's just insane. Ditto the . operator.
"Yes, but you can do some really clever things with those!", the C++
brains cry. Yeah, and i'll do something really clever with *your face* if
you try it, says i.
On Thu, 8 May 2008, Owen Jacobson wrote:
There are also some weird edge cases (like time) where the operands
and result of operations are not the same type.
There are also some distinctly non-weird non-edge cases where this is
true, and where the operands are not the same type, and where you want to
be able to overload the operators according to operand type. An obvious
example would be a Vector3D; i want to be able to add two vectors to make
a third, but also to multiply a vector by a double to get a vector, and a
vector by a vector to get their dot product, which is a double. If i also
have Matrix3D (being a 3 x 3 matrix, to represent linear transformations),
i want to be able to add matrices, to multiply two to make a third
(although i have no idea what the geometric significance of that is!), to
multiply a matrix by a vector to make a transformed vector, etc.
I can't see how you'd do this with interfaces unless they were defined as
taking Object and returning Object, which would be a bit lame.
As others have already suggested, a solution like
public interface Addable<A, S> {
public S add (A addend);
}
with generic "S"um and "A"ddend types makes the most sense. It's
just, like so much in Java, unpleasantly verbose in the simple case --
a number-like class (for example, BigDecimal) would become
public class BigDecimal implements Addable<BigDecimal, BigDecimal>,
Comparable<BigDecimal>, ...;
That's a lot of "BigDecimal"s.
A bit of syntactic sugar which let 'this' stand for the current declaring
class might help.
And since BD is not final, most of those generic types might have to be
? extends BigDecimal.
Urgh, is that how generics work? I'm not very au fait with them.
Also, can i declare:
public class Vector implements Multipliable<double, Vector>,
Multipliable<Vector, double>, Multipliable<Matrix, Vector>
?
Like how equals and compareTo work.
Comparable is a generic interface (and under this scheme I'd recommend
just using it as-is to implement >, <, <=, and >=), so its compareTo
method takes "the right type".
Actually, that highlights another issue -- what to do with comparison
operators? == has a well-understood existing meaning (identity
comparison) that would be *very* expensive to change, as do = and !=;
===, :=, !==, =!, and <> are all ugly options.
I don't see what's so bad about === and !==. In an ideal world, where we
had operator overloading from the start, ==/!= would be the ones that punt
to equals(), and ===/!== would be the ones that do identity. Like in pyhon
:).
tom
--
For the first few years I ate lunch with he mathematicians. I soon found
that they were more interested in fun and games than in serious work,
so I shifted to eating with the physics table. There I stayed for a
number of years until the Nobel Prize, promotions, and offers from
other companies, removed most of the interesting people. So I shifted
to the corresponding chemistry table where I had a friend. At first I
asked what were the important problems in chemistry, then what important
problems they were working on, or problems that might lead to important
results. One day I asked, "if what they were working on was not important,
and was not likely to lead to important things, they why were they working
on them?" After that I had to eat with the engineers! -- R. W. Hamming
---910079544-895386277-1210291270=:10697--