Growing the Java Language

11 points by soareschen


gf0

I think the word ‘Java’ scares a lot of people away, but this is an absolutely phenomenal talk about the expression problem and how it might be solved for Java.

TLDW: Java might get a feature similar to Haskell’s typeclasses, but integrated very elegantly into the language with very minimal changes: publishing and finding so-called witnesses.

A witness is an instance of an interface (think of an ordinary Comparator instance), publishing them is simply having a field or a method marked with a witness keyword.

Finding a witness is simply looking up the named types in the expression.

An example will make it clear:

interface Comparator<T> {
  int compare(T a, T b);

  public static witness Comparator<Optional<T>> lift(Comparator<T> c) {
    // We can automatically derive a Comparator for "Maybe" values as well
  }
}

class MyInt {
  public static witness Comparator<MyInt> defaultComparator = //impl
}

void useSite() {
  List<MyInt> list = ..;
  list.sort(Comparator<MyInt>.witness); //but we would find one for Comparator<Optional<MyInt>> as well
}

The resolution of .witness happens at compile-time, and is a good target for inlining.

Better generics with constraints are not yet coming, but this feature can be used to add “hooks” into the language letting it grow. An existing example would be the ‘for each’ syntax sugar, applying to instances of the Iterable interface, but now this can be used to express type-level contracts.

Examples enabled by this feature given in the talk were numeric types that may come with Valhalla (Java’s value types project), e.g. a Float16 type can declare that it can do widening conversions to double. Also, ‘operator overloading’ is still a “linguistic minefield”, but the problem is the “overloading part”, when people use it for e.g. doing IO. Given an interface applying to only numeric types, the plus operator can finally apply to e.g. a custom Float16 (but not to a list of T, so code will still be readable).

Float16 a = new Float16(32.3);
a + a;
// Would resolve to ArithmeticOps<Float16>.witness.plus(a) which can be effectively optimized as the witness is basically a constant

Another example were collection literals and default values that could reuse this same feature.

oconnor0

I’m torn. On the one hand, this design seems way more thought through than some similar thoughts on C# at https://www.youtube.com/watch?v=VPkJpaTvIC8, and Brian seems far less eager to break Java than Mads is eager to break C#. But on the other hand, it doesn’t solve the expression problem like it sounded like he was going to address in the talk.