warpedjavaguy

Imperative by day and functional by night

Closure Syntax Wars


Closures look weird and complicated but so does all other code in general.
 

There seems to be some disagreement amongst the Java community about what the exact syntax for Java closures should be. The two currently most popular closure proposals are BGGA and FCM and they each use a different syntax. Neither syntax is final and looking at the discussions and comments in recent polls and many various blogs it is evident that we all have our own opinions, preferences, and personal favourites (myself included). And as developers why shouldn’t we? We are the ones that will potentially have to write and maintain code that uses closures. That’s why we care about the syntax.

The current BGGA proposal uses the ‘=>’ syntax. Although this looks like an arrow that points to a block of code, it can sometimes trick the eye and easily be mistaken for the ‘>=’ and ‘<=’ conditional operators. Consider the example below which defines a function that returns a boolean and accepts a parameter of type int and compares it against two variables.

{int => boolean} f = { int x => y <= x && x <= z };

Now consider the same example using the current FCM ‘#’ syntax. This style is designed to look and feel like Java method signatures. It is less confusing and easier to grasp though.

<ol>
  <li>(boolean(int)) f =  #(int x) { y <= x && x <= z };

In my previous post I questioned why we shouldn’t consider Java Method Pointers (JMP). The inspiration for this was a familiar but variant form of the C/C++ function pointer syntax. The same example would look something like this:

boolean* (int) f = (int x) { y <= x && x <= z };

Closures are indeed an alien concept to Java and they sure look alien too. Throw generics into the mix and they can look even more weird and complicated.Take a look at the following two examples:

Neal Gafter’s closures puzzler which transforms a list of objects of type T to a list of objects of type U.

static  List<U> map(List list, {T=>U} transform) {
  List<U> result = new ArrayList<U>(list.size());
  for (T t : list) {
    result.add(transform.invoke(t));
  }
  return result;
}

Stephen Colebourne’s evaluating BGGA example which converts an object of type T to an object of type U.

public  {T => U} converter({=> T} a, {=> U} b, {T => U} c) {
  return {T t => a.invoke().equals(t) ? b.invoke() : c.invoke(t)};
}

At the end of the day, we really want closures in Java for doing these nice things:

  • Simplifying anonymous class instance creation
  • Automating resource management/termination (ARM blocks)
  • Using for-each style loop constructs
  • Writing less boilerplate code

Closures would make it all possible. A lot of the complicated closure constructs involving generics would be integrated into the API. Developers would not have to write those. Java would provide them out of the box.

The more you look at closures and read about them the more familiar and less alien they become. Just like everything else, they do take a little getting used to. The question is what closure syntax do we want to get used to? Will it be good for Java? One day we may have to decide. Until then, the syntax war will continue.

About these ads

Written by warpedjavaguy

February 28, 2008 at 12:14 pm

Posted in java, programming

Tagged with

6 Responses

Subscribe to comments with RSS.

  1. The significance is that developers _could_ write those complex constructs themselves rather than only in the API.

    Some treat this as bad because badly trained monkeys might produce unintelligible code.

    I say that’s what policy, code review, training and hiring good people is about – people are abusing the features of the language already but I’m glad we have the features we do when we need them… I’d have a couple of good uses for closures day #1 and they’ll all simplify code.

    Talden

    March 4, 2008 at 12:02 pm

  2. Yes, we would definitely have a need to write complex constructs ourselves, but not the ones already in the API.

    WarpedJavaGuy

    March 4, 2008 at 9:50 pm

  3. I’m not sure that closures are needed as BGGA or FCM. They’re complicated solutions to simple problems.

    Anonymous class instance creation can be done just fine by making the compiler smart about interpreting what you write.

    Taking the classic comparison example, observe the following chain:
    Collections.sort( list , new Comparator() { public int compare(Integer a,Integer b) { return a-b; } } );
    // There’s only one method, use an easier way to pick it out:
    Collections.sort( list , new int Comparator.compare(Integer a,Integer b) { return a-b; } );
    // The interface requires type matching of arguments, so
    Collections.sort( list , new int Comparator.compare(a,b) { return a-b; } );
    // Sort requires a type-matched comparator
    Collections.sort( list , new int compare(a,b) { return a-b; } );
    // compare is the only method not in Object
    Collections.sort( list , new int ?(a,b) { return a-b; } );
    // We obviously want a new thing that returns a value
    Collections.sort( list , int ?(a,b) { a-b } );

    You don’t need first-class methods or anything. The last is more compact than anything suggested by closures, is completely unambiguous, and is a simple matter of making the parser understand sensible defaults. If there is no sensible default, it’s a compile-time error.

    If anything, closures would get in the way of allowing sensible-defaulting to reduce all the redundantly unnecessary code one has to write at the moment.

    ARM can be done just like foreach iterators are done now:

    interface Resource
    {
    void acquireResource();
    void releaseResource();
    }

    (You could do this fine without generics also.)

    Now, anything that has resources implements the interface, and we interpret:

    try ( my_object ) { . . . }

    as

    my_object.acquireResource();
    try { . . . }
    finally { my_object.releaseResource(); }

    No perplexing return-does-different-things needed like in BGGA; it just works, and in the manner of foreach.

    Speaking of foreach, closures let you cover every case (with questionable clarity), but what are the common cases?

    Dual iteration has a natural extension:
    for (String s : stringlist ; double d : numberlist)
    { System.out.println(s + ” has value ” + d); }

    Subdivision of complex iterators have a natural extension:
    for (String s,double d : hashmap)
    { System.out.println(“Key ” + s + ” has value ” + d); }
    where this is specifically smart enough to understand key,value pairs.

    Anyway, making the language require a lot less unnecessarily repetitive typing doesn’t require closures at all. There are other solutions that fit better with the language structure and which solve the problems better.

    Closures/lambda functions can be useful if you don’t have inner classes, or if you don’t have robust types. I can’t see how Java benefits from them in any interesting way.

    Rex

    March 14, 2008 at 6:10 am

  4. Rex,

    Sensible defaults and compiler interpretations are one thing but powerful abstractions and actual closures are another.

    Full closures would provide Java with a more complete and extensible solution. They would solve all the common problems already mentioned and allow developers to solve even more. A lot more! A compiler/parser solution would be too limiting for developers and would not add any value to the API. Full closures would add a lot of value.

    The closure syntax is what really concerns me though.

    WarpedJavaGuy

    March 17, 2008 at 11:31 pm

  5. Somehow i missed the point. Probably lost in translation :) Anyway … nice blog to visit.

    cheers, Ride
    .

    Ride

    June 19, 2008 at 2:37 am

  6. I really like the Java Method Pointer syntax. It’s perfect in my mind and way better than “fat arrow” notation.

    Mario

    October 1, 2008 at 4:38 am


Comments are closed.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: