Stephen Colebourne on comparing closure specs

Home

News: Stephen Colebourne on comparing closure specs

  1. Stephen Colebourne has posted "Comparing closures - CICE, BGGA and FCM," looking at how three closure specifications (Lee/Lea/Bloch - CICE, Bracha/Gafter/James Gosling/von der Ahé - BGGA, and himself/Stefan Schulz - FCM) do some fairly likely tasks, including some examples that other languages use to illustrate closures. The examples use equivalent Java 6 code first, then show some possibilities with each of the closure specs. It may have been more interesting to see the closure specifications' offerings first, just to give an idea of how easy they actually are to understand:
    • CICE:public void init(JButton button) { button.addActionListener(ActionListener(ActionEvent ev) { handleButtonPress(ev); // a method in the class }); }
    • BGGA:public void init(JButton button) { button.addActionListener({ActionEvent ev => handleButtonPress(ev); }); }Alternatively:public void init(JButton button) { button.addActionListener(ActionEvent ev : ) { handleButtonPress(ev); } }
    • FCM:public void init(JButton button) { button.addActionListener(#(ActionEvent ev) { handleButtonPress(ev); }); }Alternatively:public void init(JButton button) { button.addActionListener(this#handleButtonPress(ActionEvent)); }
    The Java 6 code uses an anonymous inner class to invoke handleButtonPress(ActionEvent). The "multiply two integers" example is a whole lot of code just to do "x*y" with functional programming, but highlights creation of a new class with a specialized method. Here are the examples:
    • CICE:public int multiplier = 3; IntMultiplier mult = new IntMultiplier() { public int multiply(int value) { return value * multiplier; } }; int result = mult.multiply(6);
    • BGGA:int multiplier = 3; {int => int} mult = {int value => value * multiplier }; int result = mult.invoke(6);
    • FCM:int multiplier = 3; #(int(int)) mult = #(int value) { return value * multiplier; }; int result = mult.invoke(6);
    Mr. Colebourne is biased (as he readily admits), having co-authored the FCM specification, but he's done a good job providing simple examples for each of the closure specifications being proposed. Which one of those seems most clear? Which one of the three are you most likely to prefer writing? Are any of these going to make closures worth including in Java 7?

    Threaded Messages (25)

  2. In my opinion closures without type inference is adding complexity, not removing it. In all of the examples we had to add new syntax just for defining the functional types. It most probably would be a lesser evil to just allow the compiler to infer (locally) types and pass closures instead of one-method interfaces. This would only require new syntax for specifying block arguments, which would never show up in contracts. Jevgeni Kabanov www.araneaframework.org
  3. In my opinion closures without type inference is adding complexity, not removing it.
    Type inference is already being proposed elsewhere, so this proposal will hopefully benefit from that. Adding it in this proposal, one might end up being incompatible with whatever type inference makes it into Java. Plus, it makes the spec somewhat easier to understand, not to mention type inference.
  4. Why not[ Go to top ]

    Why not use the following: { String a; | System.out.println( "Hello " + a ); }.value( "World" ); The most important thing is that block can be assigned to a variable, so: Block m = { String a; | System.out.println( "Hello " + a ); }; m.value( "World" ); It shouldn't be more complicated than that. If the "|" character is not welcome, here is an alternative: new Block( String a ) { System.out.println( "Hello " + a ); }.value( "World" ); So again this could be written: Block m = new Block( String a ) { System.out.println( "Hello " + a ); }; m.value( "World" ); That is pretty consistent with current Java.
  5. Re: Why not[ Go to top ]

    There are two components to any language change - syntax and semantics. Syntax only matters in terms of visual appeal, verbosity and clarity, and is often subjective. Semantics are far more important, as they define what the code actually does. Your proposal to use a | and move the parameters inside the block is simply a syntax change. Having written FCM, I'd say it wasn't as clear, but others will disagree. Its subjective and a matter of taste. However, your proposal to assign to a Block class is a semantic change. I don't believe that it is acceptable as blocks can have different numbers of parameters, and different return types. Put simply, using a single 'Block' class means that type-safety is lost.
  6. OMG, you can't be serious[ Go to top ]

    I can't believe what I'm seeing. Supposedly a simple concept of closures, is turning into a syntax nightmare. I don't see why all of this syntax is needed. What's wrong with either creating a method type... int multiplier = 3; Method m = int comput(value) { return mutliplier * value; } int result = m.invoke(3); Even the current workaround with anonymous inner classes, just with allowing non-final fields, would be easier to understand/use. Overall, I think CICE implementation is more sane. Ilya
  7. Re: OMG, you can't be serious[ Go to top ]

    sorry, I mistyped... int multiplier = 3; public method m = int method(int value) { return multipler * value; } int result = m.invoke(3);
  8. Re: OMG, you can't be serious[ Go to top ]

    If all method references have the same type it's like using java.lang.Object for all object references. Java cannot compromise type safety. Taras
  9. Re: OMG, you can't be serious[ Go to top ]

    sorry, I mistyped...

    int multiplier = 3;
    public method m = int method(int value) {
    return multipler * value;
    }

    int result = m.invoke(3);
    You can just use: int result = m(3);
  10. Re: OMG, you can't be serious[ Go to top ]

    What's wrong with either creating a method type...

    int multiplier = 3;
    Method m = int comput(value) {
    return mutliplier * value;
    }

    int result = m.invoke(3);

    Method, assuming you mean java.lang.reflect.Method, can throw some exceptions when you call invoke. In your example, what use is the name 'comput'? You could just do Method m=int(value){stuff}. Of course, that starts to look like a method call instead, but at least we're not giving names to things that don't need them. How does the compiler know what type to give value? Wouldn't you need Method m=int comput(int value){stuff}? I'm not sure that's much of a win over #(int(int value)){stuff}. Without the unnecessary name, comput, yours looks like int(int value){stuff}, which is only a # and a pair of () away from the proposal. Further, FCM solves another issue, allowing you to refer to existing methods. The # allows both issues to be solved with reasonably similar syntax.
  11. CICE looks like status quo[ Go to top ]

    I'm having trouble seeing how CICE is any different from the inner classes we have now. Oh ... it's just a sleight-of-hand rebinding of 'this'. How vastly unimpressive. As for which I prefer: none of them. They're all a godawful soup of overcomplicated syntax. Here's the syntax I want: button.addActionListener(handleButtonPress); Is it too hard to figure out this basic freaking idea of first-class functional values? Have I grossly overestimated the intelligence of Java's custodians?
  12. on overestimating intelligence[ Go to top ]

    It occurs to me that ambiguous conditions can appear in the face of overloading and covariance, so there needs to be some means of adding type annotations to resolve which instance of handleButtonPress you need, if it comes to that -- and probably 95% of the time, it won't. In this case, something like FCM without the noisy punctuation wart wins out for me. I don't know what the replacement is, figure it out. Maybe a new keyword? I suspect that the proposal that does the very least and has the names of the most Java insiders attached to it will win. Score another win for every language but Java. Yes, I'm bitter.
  13. Your solution is vastly superior to any of the ones I have seen so far. Quite similar to the way .Net does it, if I remember correctly.
  14. Re: CICE looks like status quo[ Go to top ]

    Here's the syntax I want:

    button.addActionListener(handleButtonPress);

    Is it too hard to figure out this basic freaking idea of first-class functional values? Have I grossly overestimated the intelligence of Java's custodians?
    button.addActionListener(handleButtonPress) is already valid syntax, and will refer to a field. If you make it also able to refer to a method, that will be ambiguous in some cases, as Java allows fields and methods to have the same name as each other. There would need to be a rule, such as "if there is a field and a method, and both are visible, use the field". I expect this would be workable, but cause confusion in some cases. The FCM allows what you want, except that currently you have to specify the types, and add a #, so you get: button.addActionListener(#handleButtonPress(ActionEvent)); It is an open issue in the proposal as to whether to require the types when the method isn't overloaded: "5. Is there a shortcut syntax to avoid specifying the types in a method literal or invocable method reference when the method is not overloaded, for example Object#equals(...)"
  15. Re: CICE looks like status quo[ Go to top ]

    It is an open issue in the proposal as to whether to require the types when the method isn't overloaded:

    "5. Is there a shortcut syntax to avoid specifying the types in a method literal or invocable method reference when the method is not overloaded, for example Object#equals(...)"
    My gut reaction is to consider the issue closed -- it shouldn't require the type, ever. Possibly this runs into problems with late binding, but then again you get the problem anyway. As for ambiguity between methods and fields, if functions were real actual types (no, reflection does not count) then this simply wouldn't be a problem. addActionListener would be overloaded to take an ActionEvent->void type, and handleButtonPress would be selected as the more specific type. Now if there actually was ambiguity, I'd expect the compiler to call it an error and require an explicit type signature (you could abuse the typecast syntax for this, or *sigh* use reflection). All right, though, I'll admit that the Java designers don't want methods suddenly appearing in a namespace that was formerly populated by locals, with special rules on which one is selected. My personal attitude is "too bad, we have overloading anyway", but I can concede the need for a syntax. And # is decent, it's reminiscent of smalltalk. And there goes another piece of punctuation that can't easily be used by anything else in the future -- we're getting painted into a corner here when we don't have the ability to program syntax.
  16. Re: CICE looks like status quo[ Go to top ]

    Here's the syntax I want:

    button.addActionListener(handleButtonPress);

    Is it too hard to figure out this basic freaking idea of first-class functional values? Have I grossly overestimated the intelligence of Java's custodians?


    button.addActionListener(handleButtonPress) is already valid syntax, and will refer to a field. If you make it also able to refer to a method, that will be ambiguous in some cases, as Java allows fields and methods to have the same name as each other. There would need to be a rule, such as "if there is a field and a method, and both are visible, use the field". I expect this would be workable, but cause confusion in some cases.

    The FCM allows what you want, except that currently you have to specify the types, and add a #, so you get:

    button.addActionListener(#handleButtonPress(ActionEvent));

    It is an open issue in the proposal as to whether to require the types when the method isn't overloaded:

    "5. Is there a shortcut syntax to avoid specifying the types in a method literal or invocable method reference when the method is not overloaded, for example Object#equals(...)"
    Politically speaking, Sun Microsystems made a huge stink when Microsoft added function pointers to Java without permission, claiming that it screwed up the language. What's being talked about here is very nearly that. But I myself think function pointers would be just fine.
  17. Need better examples[ Go to top ]

    IMO, the goal of closures is to enable better API-s, like generics have done. Swing API has already found a way to use closures-like anonymous inner classes. The biggest opportunity for closures is in other API-s: - Each method that returns an Iterator/Enumeration (or enables iteration in some other way, like through ResultSet) is candidate for alternative forEach() method - When you have openXXX()/closeXXX() or beginXXX()/endXXX() methods (or whenever try-finally is recommended), you may consider closure based withXXX() method, like withTransaction() Also, nice syntax for closure invocation and closure type definition is less important, it is usualy part of an API implementation. Something like control invocation syntax (part of BBGA) is my favorite. Triple ")};" is just too noisy. Nebojsa
  18. Re: Need better examples[ Go to top ]

    I second that these need better examples and that who cares about closures in the context of Swing really. Nor is this a great example of the most powerful advantages of each proposal. Here is my example based on the "BGGA": http://blog.buni.org/blog/acoliver/Tips/2007/03/01/Removing-AOP-magic-with-Java-Closures-and-Java-Closure-method-assignment Transaction.required { ... } Now show me the user API version of the others. (I only used that particular one as an example because he explained it so well in the google video ;-) )
  19. Re: Need better examples[ Go to top ]

    Neal Gafter: http://www.bejug.org/confluenceBeJUG/display/PARLEYS/Closures+for+Java
  20. Re: Need better examples[ Go to top ]

    Neal Gafter: http://www.bejug.org/confluenceBeJUG/display/PARLEYS/Closures+for+Java
    My comments to the proposal: I prefer "lock.with(..." over "Lock.withLock(lock...", or "myCollection.forEach(..." over "forEach(myCollection...". BTW, am influenced by Smalltalk when think about closures. Syntax "c.forEach(Item t :) {...}" is closest to my expectations. But do we need colon? Why don't use "c.forEach(Item t) {...}" and "lock.with() {...}". Isn't opening curly bracket after closing parenthesis enough to denote new syntax? Nebojsa
  21. A number of replies have focussed on the control invocation syntax of BGGA, which allows you to do the following: Locks.withLock(lock) { // some code protected by the lock } Both CICE and FCM deliberately do not tackle this type of syntax, however they do so for different reasons. The authors of CICE (Josh Bloch notably) do not believe that developers should be allowed to write code in this style. They believe that only language designers should be able to make changes that look visually like keywords. The authors of FCM (ie. Stefan and I) believe that a control invocation syntax is very useful, but we think it should be considered separately to proposals to simplify working with methods. We believe that BGGA has greatly complicated matters by attempting to cover both in the same spec.
  22. The authors of CICE (Josh Bloch notably) do not believe that developers should be allowed to write code in this style. They believe that only language designers should be able to make changes that look visually like keywords.

    The authors of FCM (ie. Stefan and I) believe that a control invocation syntax is very useful, but we think it should be considered separately to proposals to simplify working with methods. We believe that BGGA has greatly complicated matters by attempting to cover both in the same spec.
    In real world applications, I expect almost 100% of closure literals will be parameters of method calls. So, syntax for "method call with a closure parameter" is primary use case, even more important then closure literal syntax itself. You may put only this syntax in a proposal and it makes sense. I like functional programming, but I think that all proposals are too focused on functional programming aspect of closures. So, I agree that we should separate proposals to simplify working with methods and proposals on the rest of closures aspects, but I have different opinion what is priority. I also, agree that changes that look visually like keywords are not good and a comment in my previous post goes in this direction. Nebojsa
  23. One thing that really bugs me about FCM is that they are overloading the hash (#) symbol. How will they resolve this with Java-7's XML integration, where this was used in the proposed syntax at JavaOne? (http://blogs.sun.com/mr/resource/integrating-xml-j1-2006.pdf) I tend to like CICE because it stays the truest to the language and is the most obvious to new users and old timers alike. I don't like weird syntax that gets away from Java's core value of simplicity. (Heck, I'd have prefered a new keyword than the ':' for /for each/, but alas..)
  24. Native XML[ Go to top ]

    I'm betting that native XML won't happen - it's never struck me as a good language change idea. Stephen Colebourne, FCM
  25. Method pointer[ Go to top ]

    I've not opinion about "anonymous method"/closure. But about named, I think using function pointer like in C, is the simplest solution. public R myMethod(T1 t1) { ... } x.doStuff(methodref(this.myMethod)); public R doStuff(RefMethod method) { T1 t1 = ... return method.invoke(t1); } I think this type of binding could also be used for property/public field binding. x.bind(button, propertyref(this.myField)); * This type of syntax is already valid, and could be simulated/prototyped with a pre-processor (like spoon). * This syntax use the IDE completion and validation (no string)
  26. I am having a conversation with Stephen and Stefan regarding their proposal and its relationship to the goals of BGGA. Stephen tells me that "We intended FCM to be mostly about syntax sugar, providing a better syntax for code that can be written today. Thus most FCM syntax would simply substitute the existing matching code." and "Stefan and I are still discussing ideas on a control-invocation syntax that would be a complementary document to FCM, and not part of it. This would be specifically to tackle the synchronous use cases" I think there are some good ideas in FCM, but I'm suspending judgment until I see the full complement of features proposed.