Re: operator overloading
On May 8, 8:10 pm, Tom Anderson <t...@urchin.earth.li> wrote:
On Thu, 8 May 2008, Owen Jacobson wrote:
On May 8, 1:52 pm, Tom Anderson <t...@urchin.earth.li> wrote:
You could even model a little hierarchy on discrete mathematics: Addabl=
e,
Multipliable, Ring extends Addable, Multipliable, Dividable, Field exte=
nds
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?
It's worth looking at the way Haskell handles operator overloading and
numeric types here. There is a class of types, Num, which represent
"numbers": integers, reals, rationals, complex numbers, oddities like
quaternions, presumably the tensor family, whatever. Num provides +,
-, *, negate (used for unary -), and abs functions, and inherits
equality testing from the Eq class.
Num has a subclass, Real, which also subclasses Haskell's Ord class,
which in turn provides comparison operators. This is the root of most
the more common numeric types, not Num.
Real has two subclasses: Integral and Fractional. Both provide the /
operation; the difference is in the result type. Integral in turn has
two subclasses: Integer, which are bigints, and Int, which are
intended to be machine ints. Dividing two Integral values can only
produce another Integral; Integral also provides remainder and mod
operations.
Fractional's standard instances are the Float and Double types, which
map to what you'd expect from other languages. Fractional specifies
a / operator as well as a few other useful things.
Due to the way type classes work in Haskell it's extremely easy to add
new numeric types at arbitrary points in this tree and have them work
"as expected" with existing code. Your hypothetical Giant Matrix type
would likely be an instance of Num, and would add some operators of
its own to allow for multiplication by non-Giant Matrix values like
Reals.
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!
You've a call from the org.omg package complaining about unfair
representation. ;)
Aside from the "obvious" cases like CORBA support, there is very
little in the Java SE library that I would opt to remove. The XML
support could use some streamlining, perhaps; it's gotten overgrown as
Sun has gotten in the habit of declaring the XML library of the week
to be "standard" and adding it. So I suspect we disagree there, or
are thinking of different definitions of "standard library" (and if
you start including Java EE or other javax.* packages that aren't part
of the Java SE library, I'd certainly agree with you).
Library design, as ever, is a series of rather hard tradeoffs. :)
(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.
If your objects are million-by-million matrices, I would hope that you
have some kind of sparse matrix structure, or some other compositional
representation that doesn't actually hold all trillion elements in
memory simultaneously. Large isn't *necessarily* slow, if you're
clever.
One thing we definitely shouldn't have is overriding of the = operator,
as C++ lets you do. That's just insane. Ditto the . operator.
No argument from me. The . and = operators only make sense in C++
because C++ has objects-as-values. I'd add -> to the list (even
though the Java equivalent is .), since object indirection is a fairly
core part of the language and I don't want anyone monkeying with it.
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.
It Depends On What You Want. If, eg., BigDecimal implements
Comparable<BigDecimal> (which it does), and you subclass BigDecimal as
MyBigDecimal (which you can), then you wind up with MyBigDecimal
implementing Comparable<BigDecimal>, which is actually what you want
(as it allows clients to compare objects of your subclass to arbitrary
BigDecimal objects).
I hadn't thought through the implications completely when I wrote
that, hence the "might"; now that I have time to sit and play with it
a bit I think they could just be <BigDecimal> type constraints and the
semantics would come out okay.
Also, can i declare:
public class Vector implements Multipliable<double, Vector>,
Multipliable<Vector, double>, Multipliable<Matrix, Vector>
?
No, as double is not a reference type; no, as you can't implement an
interface more than once and all those generic specializations are
really the same interface. The former can be worked around with the
language as-is; the latter cannot. Allowing that would involve
changing the way method overloads are resolved, or adding rules to
forbid implementing both Multipliable<Double, Vector> and
Multipliable<Vector, Vector> - as it stands, you can't provide both
public Double multiply (Vector) and public Vector multiply (Vector) in
the same class, because the only distinction is the return type.
--
[The sig that ate Manhattan...]
Jesus H! McQuary limit, anyone?