Daniel Pitts’ Tech Blog

Posts Tagged ‘interfaces’

More Discussion On Operator Overloading

Wednesday, December 5th, 2007

Updated: See notes below.

I was surprised to see that within one day of posting my previous entry on Operator Overloading, I received several comments. Aviad Ben Dov from Chaotic Java even took my idea and ran with it. Ricky Clarkson suggested using Haskell’s approach of allowing anything that is of the “Num” type to define +,-,/,*, etc…. I have a few things to add to this discussion.

Aviad’s idea for operators by interface is not a bad one; it works well for overloading “[]” but it breaks down on a few use cases (such as ‘+’, ‘*’, etc..) that are important (to me). Ricky’s idea for subtypes of a specific class getting to have operator overloading isn’t bad either, but for physical unit manipulation it is too inflexible. The core concept that both of them seem to have suggest is that a limited selection of types can have overloaded operators, but the operations that are possible aren’t limited to the scalar quantities that this would limit the operators to.

Suppose I have the classes Distance, Area, and the built-in “Scalar” type Double I would expect at least these sets of operations:
Distance * Distance => Area
Distance * Double => Distance

If I had to implement the Multipliable<T> interface, I wouldn’t be able to handle Distance * Distance and Distance * Double. You can’t implement an interface twice, even with different type parameters. I don’t know if this is something that Reified generics would fix, but it feels like it might be. Maybe someone could comment on that.

Also, if Distance had to extend Number, what would doubleValue return? Meters? Inches? Smoots? There might be some way to solve these problems, but I can’t think of a way to prevent abuse while allow good use.

Actually, now that I have thought a little about it…

The semantics of plus (+), minus (-), times (*), dividedBy (/), moduloOf (%), shiftLeft(<<), shiftRight(>>), unsignedShiftRight(>>>), or(|), and(&), xor (^), negative(-), and inverse(~), are all well-defined enough for so many not-necessarily-numeric types that allowing, even if only through naming conventions, the overloading of those operations seems like a good idea.

I think a good way to go would be to convert at compile time a * b to the method call a.times(b). Assignment operators like a += b would be replaced with a = a.plus(b). This would help reduce abuse while creating a more expressive language. The assignment operator rule is important, as it will help prevent the “clever” idiom of using += for appending elements to a collection.

Note on updates: I previously misspelled Aviad as “Avaid”. I also have added clarification for which use-cases Aviad’s Indexer doesn’t work for me, namely for algebraic operators.

Type Intersection in Java, or: Interest in Interfaces is Invaluable.

Tuesday, March 6th, 2007

There was an interesting philosphical question posted in the comp.lang.java.programmer newsgroup the other day. Patricia, the original poster, had a question about using ArrayList as the declared type. She wanted to convey the fact that she wanted a List which has constant time random access methods, as this is an important property for her algorithm. Many of us live by the rule “Always use an interface, never a concrete type,” and she was questioning this. I personally think this dogma is a little to broad. However, it usually makes sense when using Java collections. As a matter of fact, you’ll find a lot of my code uses Collection instead of Set or List.

I guess Sun also thought it was important to convey constant time random access; they created an interface called RandomAccess just for that. RandomAccess is a marker interface for a List implementation to “indicate that they support fast (generally constant time) random access.”

Thats all well and good, but there’s a problem here.

   RandomAccess myList = new ArrayList<Integer>(); // This compiles fine

   myList.get(0); // Whoops, compile error. RandomAccess doesn't extend List, so no get method;

Java 1.5 *almost* supports what we want… We want to say “Give me an object that is RandomAccess AND List<Integer>”. With the introduction of Generics, Java introduced Type Intersection. Unfortunately, they only introduced it in the context of Generics.

  // Processes a RandomAccess List of integers, compiles fine

  public <L extends RandomAccess&List<Integer> > void processList(L list) {
      // ...
  }

  // Fails to compile.
  public List<Integer> process(Collection<Integer> input) {
    RandomAccess&List<Integer> output = new ArrayList<Integer>(input);
    //  ...
    return output;
  }

While this is too convoluted to answer Patricia’s philosophical question. It does bring us to an interesting, if incomplete, feature of Java.

(more…)