Java Lambda Syntax Alternatives
The Perl people have a nice example of something which uses function references in a somewhat functional way – they call it the Schwartzian Transform (but I believe it’s originally a Lisp trick sometimes called decorate-sort-undecorate). As there are just us JVM chickens here, I rewrote it in Clojure (it’s actually one of my examples in Chapter 9 of the book).
Here’s a snippet of Clojure code which defines a function to perform the Schwartzian transform. Basically, it provides a very simple way of sorting a list based on an auxiliary function (called a “keying function”) provided by the caller.
(defn schwarz [x f] (map #(nth %1 0) (sort-by #(nth %1 1) (map #(let [w %1] (list w (f w)) ) x))))
The code is doing three separate steps – creation of a list consisting of pairs (the original values paired up with the value obtained by applying the keying function to the original values), then sorting the pairs based on the values of the keying function. Finally a new list is constructed by taking only the original value from each pair in the sorted list-of-pairs (and discarding the keying function values).
What might this look like in the various proposed Java syntax variants? Let’s take a quick look at each one (note that because Java’s type system is much more static, a lot of our type declarations are more than a little long-winded):
// Strawman, with round brackets for single-expression lambdas public List<T> schwarz(List<T> x, Function<T, Pair<T,V extends Comparable<T>>> f) { return map(#(T w)(makelist(w, f.apply(w))), x) .sort(#(Pair<T, V extends Comparable<T>> l)(l.get(1))) .map(#(Pair<T, V extends Comparable<T>> l)(l.get(0))); } // Strawman, with braces for all lambdas public List<T> schwarz(List<T> x, Function<T, Pair<T,V extends Comparable<T>>> f) { return map(#(T w){makelist(w, f.apply(w))}, x) .sort(#(Pair<T, V extends Comparable<T>> l){l.get(1)}) .map(#(Pair<T, V extends Comparable<T>> l){l.get(0)}); } // BGGA public List<T> schwarz(List<T> x, Function<T, Pair<T,V>> f) { return map({T w -> makelist(w, f.apply(w))}, x) .sort({Pair<T, V extends Comparable<T>> l -> l.get(1)}) .map({Pair<T, V extends Comparable<T>> l -> l.get(0)}); } // SotL public List<T> schwarz(List<T> x, Function<T, Pair<T,V>> f) { return map(#{T w -> makelist(w, f.apply(w))}, x) .sort(#{Pair<T, V extends Comparable<T>> l -> l.get(1)}) .map(#{Pair<T, V extends Comparable<T>> l -> l.get(0)}); } // Redmond public List<T> schwarz(List<T> x, Function<T, Pair<T,V extends Comparable<T>>> f) { return map((T w) -> {makelist(w, f.apply(w))}, x) .sort((Pair<T,V extends Comparable<T>> l) -> {l.get(1)}) .map((Pair<T, V extends Comparable<T>> l) -> {l.get(0)}); }
How to evaluate them? My criteria are:
- Needs to start with a visible identifying mark, so that lambdas stand out from the surrounding code. The # is a handy character for this.
- Needs to use the {} delimiting syntax. Closures are a kind of block, so they should be block-like in code.
- Needs to be all in one piece, so the syntax has a visual consistency and the lambda appears as a single unit.
- Preferably, needs to have a specialized short form for function literals which take no parameters (nullary lambdas).
Based on these criteria, Redmond is the worst possible choice for me – and my experience writing Scala for the book bears this out – I found Scala’s function literals much harder to use without problems than those in other languages. BGGA is a little better, but I don’t like the lack of a simple identifying mark that tells me “Hello! I’m a lambda”.
This brings it down to a choice to between SotL and Strawman with always-brace. The choice of these two is somewhat arbitrary. Strawman-always-brace looks, to my eyes like a true Java method declaration, but with the “magic name” # – whereas SotL is genuinely new syntax, but feels closer to the Redmond and BGGA styles – so could well be an acceptable compromise for developers who are comfortable with those forms.
Pulling it all together, my preferred choices are:
- SotLhttp://www.blogger.com/img/blank.gif
- Strawman-always-brace
- BGGA
- Strawman-single-expression-round
- Redmond
Please use the comments (below or at the original source) to tell us what you make of this issue. Of course, this won’t be in Java 7 – but it’s not too early to start thinking about Java 8 and the future.
Reference: Lambda Syntax Alternatives from our JCG partners at the Java 7 Developer Blog.