Skip to main content

Chistmas Gift

Posted by forax on December 27, 2009 at 8:21 AM PST

Christmas holidays is one of my favourite moment in the year, I have time to see my relatives, read books, play with my kids and hack a little bit.

Forewords

I think I don't like the most in the strawman proposal is that the syntax for function type and for lambda literal reuse the same symbol '#'.
It's something that I've observed when teaching C. The C syntax use * when you declare a pointer type and * when you want to dereference a pointer variable. The fact that * is used twice for different meanings introduces unnecessary confusion and is a burden to understand pointers.
In my opinion, we should use a new keyword lambda to define lambda literal and use # for function type.

  #int(int) fun = lambda(int x) (x); 

But introducing a new keyword may break existing codes if by example lambda is used as a variable name, a type name, etc. So I decide to hack the javac parser to see if this syntax can be introduced without breaking all existing programs by considering lambda as a contextual keyword.

 

Defining a lambda with lambda

So I've hacked the parser. And guess whar, it's possible to distinguish between a method call named lambda and a lambda literal because in the strawman proposal lambda statement starts with a curly brace ('{') and lambda expression starts with a left parenthesis ('(').

So the hacked parser recognizes:

A lambda expression that takes an integer and returns its double:

   lambda(int x) (x + x)
 

A lambda statement that prints hello and a given text:

   lambda(String s) {
       System.out.println("hello " + s);
   }
 

Like in the stawman proposal, the return type is infered from the expression or from the 'return' contained in the statement (or void otherwise).

 

Yet another closure prototype

When you have a parser that recognize lambdas, it's very difficult to resist to don't hack all other passes of the compiler to implement a full prototype. And you known what, I'm weak.
Here is a small prototype that recognizes lambda and function types. Because lambda are translated to JSR 292 method handle. you need a recent JDK7 VM to run the compiled code or a JDK5 or 6 with the backport.

The prototype is available as a patch and as a jar with some samples.
To compile:

   java -cp lambda-tools.jar com.sun.tools.javac.Main Lamnda1.java 
 

To run (the VM will issue a warning but that's fine):

   /usr/jdk/jdk1.7.0/bin/java -XX:+UnlockExperimentalVMOptions -XX:+EnableInvokeDynamic Lambda1
 

To run with the backport:

    /usr/jdk/jdk1.6.0_11/bin/java -javaagent:jsr292-backport.jar Lambda1
 

 

The current prototype:

  • implement function type, modifiy signature attribute to enable separate compilation of method taking a function type as parameter. It also patch javap to also support function type signature.
  • implements subtyping of function types but the current JDK7 beta doesn't support it. You have to wait a next beta of JDK7 or use the backport.
  • implements lambda literal, infers return type, etc.
  • implements instance capture

but

  • doesn't capture local variable
  • doesn't implement function conversion
  • doesn't implement extension methods
  • is heavily untested :)

 

Happy new year
Rémi

Comments

got error

I tried to run the compiled code, but got some error while compiling it several times. I don't have a recent JDK7. Maybe this is a cause of the problem?

the real solution: ditch lambda expressions

Lambda expression are plain evil. All that nonsense to avoid the use of a single 'return' is...nonsense. They are to closures what non-array-support is to generics: the thing you will regret. Nobody asked for it. The real user pressure was on functions. If you really listen to the community, add the functions and then wait a year or two and see if everybody is crying to get expressions. Nobody will switch to Scala only because Java hasn't expressions. You already have enough work and decisions to make with extension methods and such.

Olivier Allouch

Make it a real keyword

I am not a fan of context-sensitive keywords. I think they are (political) hacks, and make source code less readable to the human eye. Given two options -- forcing the rename of methods/variables named 'lambda' and context-sensitive keywords -- I choose the former. When I look at source, I'd like to know that "lamda" is just that in the Java programming language. Tooling is so good nowadays that these issues in code-bases can be identified and corrected easily. Besides, it's an esoteric word. Unless you're writing math and physic libraries, who chooses that anyway?

Contextual keywords have been

Contextual keywords have been used with great success in other languagues, i.e. it's what allows C# to support such ground-breaking stuff as LINQ. Sometimes we have to put pragmatism ahead of dogmatism - and contextual keywords solves the problem a lot cleaner than coming up with arbitrary and unusual character tokens.

Make it a real keyword

 We've got some history with adding keywords with assert.

assert() was a method name in JUnit, a very prevalent library. Does any library in common use claim lambda() as a method name? If we can swallow assert, I suspect we can handle lambda with less trouble.

 

Syntactic ambiguity...

lambda()(3) might be creating a closure of no arguments that returns the value 3, or it might be invoking the method lambda on no arguments, the result of which is of a function type, and invoking the resulting function on the argument 3.