Daniel Pitts’ Tech Blog

Archive for the ‘Almost Useful’ Category

Almost Useful: Operator overloading

Tuesday, December 4th, 2007

On suns site, there is an open bug for operator overloading. Many people have pointed out that Java has one special case of operator overloading (String + String), so why not allow the programmer to overload operators?

Operator overloading would become especially useful when the addition of the units and measures API, or other custom libraries that are similar. It becomes especially useful when trying to avoid primitive obsession, and create numeric-like types.

Imagine this case:

Speed s = endDistance.minus(startDistance).divide(duration);

could be simplified to

Speed s = (endDistance - startDistance) / duration;

This of course is a simple example, and yet one that I would love to use in some of my existing code-bases.

Another use case would be a cleaner syntax for lists/maps:

myMap["Hey"] = "There";
System.out.println(myList[10]);

And hey, what about a special case for compareTo? Although it might be too dangerous to overload =/==, I could see overloading <, > <=, and >=. It might be nice to add a couple of operators to the mix. I’m officially suggesting “#” for concatenation. Maybe “:=” for shortand to .equals().

Almost Useful: if instanceof

Friday, November 23rd, 2007

While often times if (x instanceof Y) indicates a problem that should be solved with proper use of polymorphic methods, it sometimes is unavoidable (.equals(Object o) implementation for example). A common idiom is:

if (x instanceof Y) {
  Y y = (Y) x;
}

Of course, this makes sense from a utility point of view, you know that it is a Y object, and so you want Y functionality from it. From a programmers point of view though, it is terribly redundant in many ways. In many cases, static analysis can tell the compiler that when you are in the block of that if statement, that x is indeed a Y object, why then should I be forced to cast to Y? Why can’t the compiler figure out the type for me?

This becomes even more useful if we combine the concept with the fully useful Type Intersection (Not yet implemented). If both of these features were implemented, then you could write something like:

public <T extends Comparable<T>> void sort(List<? extends T> list) {
 if (list instanceof RandomAccess) {
    /* list compile-time type here would be List<? extends T>&RandomAccess. */
    sort(list);
  } else {
    /* Other type of sort implementation. */
  }
}
public <T extends Comparable<T>> void sort(List<? extends T>&RandomAccess list) {
  /* Random access sort implementation */
}

This type of static analysis feature could be extended to predict NPE’s and redundant checks. Heck, the IDE I use tells me when I’ve accessed something when it might be null, or when my inner-if statement is a subset of the outer. It even has shortcuts for adding the cast in the if (x instanceof Y) {} blocks.

Almost Useful: Java Type Intersection.

Friday, November 23rd, 2007

First, for my subscribers that celebrate it, Happy Thanksgiving!

I’ve written about it before, but I think its worth revisiting. Type intersection would be a highly useful feature if not for one thing. “It is not possible to write an intersection type directly as part of a program; no syntax supports this.” – JLS (ยง4.9). That seems like a poor excuse to not support a feature as potentially powerful as type intersection could have been.

They were bold enough to add syntax all over the place for Generics. They added new syntatical meanings for ‘?’ ‘<’, and ‘>’. As a matter of fact, they added a syntax within that construct for handling Type Intersections. Would it really be that difficult to reuse that syntax outside of capture conversions and type inference? Heck, maybe even make it reifiable, although that’s not *as* important.

One example others have used in the past where it would be useful to have this type intersection is with the marker interface RandomAccess. While marker interfaces are less useful now that we have annotations, it none-the-less exists, and can be useful for ensuring that the user of an algorithm passes in a compatible list.

For example, its quite possible to do the following, even with the currently crippled implementation of type intersection.
<T extends List<String> & RandomAccess> void foo(T list) { ... }
You know that you’re getting a random access list. The pain point is that you can not do the following:
<T extends List<String> & RandomAccess> T foo() { return new ArrayList<String>(); }
The reason that isn’t legal is quite simple, even if its not obvious. T is any type that satisfies List<String>&RandomAccess, so you don’t know that it is an ArrayList. You might have MyNonArrayList<String> list = foo(); Oops, that would be an incompatible assignment.

The better approach would be to have the return type be an explicit type that is List<String>&RandomAccess. As a matter of fact, my suggestion is to use that syntax exactly, unless there is a compiler-grammar reason not to. So, our T foo() line becomes:
List<String>&RandomAccess foo() { return new ArrayList<String>(); }
So then we can do: List<String>&RandomAccess list = foo(); Actually, we could just use List<String> list=foo() if we don’t care about RandomAccess.

An important addition to make to this would be casting. For legacy support, if I have a List<String>, but I know that it should be an ArrayList (or some other RandomAccess), I should be able to cast: foo((List<String>&RandomAccess)list);