Home

News: Closures without Complexity

  1. Closures without Complexity (42 messages)

    Bob Lee, Doug Lea, and Josh Bloch have written up another proposal for closures in Java called "Concise Instance Creation Expressions: Closures without Complexity," offering a shorthand notation for "single abstract method" types, such as Comparators or Runnables. For these types, the suggestion omits the keyword 'new,' the class declaration, and the method name from class instance creation expressions. For example, if you use GWT, the Command interface has a single method, "execute()." With the proposal by Lee, Lea, and Bloch, this would turn code like this:MenuItem menuItem=new MenuItem("Foo", new Command() { public void execute() { Window.alert("Foo was chosen"); } });... to something like the following:MenuItem menuItem=new MenuItem("Foo", Command() { Window.alert("Foo was chosen"); });Note the lack of the declaration of the single interface method, execute(), as well as the lack of the new keyword. Much as foreach, the paper says "from the programmer's perspective, that's pretty much all there is to it: no new concepts to learn, just a more concise syntax for something they already do." A few library changes are also suggested, to make use of this closure mechanism cleaner. As Bob Lee says in "The Java Closure Spectrum",
    Loosely speaking, simple syntax sugar for anonymous inner classes buys Java 90% of the power of BGGA (short for Bracha, Gafter, Gosling, Ahe, another closure proposal's authors' last names) closures while carrying only 10% of the weight. We think it's the "knee in curve" where we get the most bang for our buck.
    What do you think? Is this proposal better than the others, and if so, why?

    Threaded Messages (42)

  2. Is this really necessary?[ Go to top ]

    Why do we need this. What is so hard to understand about the first code extract. With modern IDE's which are able to automatically generate stub implementations of interfaces is it really necessary to accomodate programming constructs such as closures just because Ruby does???
  3. Re: Is this really necessary?[ Go to top ]

    +1 All this does is that it makes it harder to learn Java in the first place. More constructs that look almost the same yet are very different.
  4. Re: Is this really necessary?[ Go to top ]

    I don't see how it makes learning Java harder. I'd rather teach either syntax instead of anonymous classes. New programmers probably find closures easy to use, but won't have a great in-depth understanding of them. When it comes in, I'll observe and possibly revise my position. For now I don't teach anything that has closures (Perl and Java).
  5. Re: Is this really necessary?[ Go to top ]

    I don't see how it makes learning Java harder. I'd rather teach either syntax instead of anonymous classes.

    New programmers probably find closures easy to use, but won't have a great in-depth understanding of them. When it comes in, I'll observe and possibly revise my position. For now I don't teach anything that has closures (Perl and Java).
    Java newbies struggle today with the distinction between static and non-static scopes. How do you expect them to cope with yet another abstraction and for what gain? Do people find that they get worn down from typing too much? You should change to a competent development environment instead of attacking the language semantics.
  6. Re: Is this really necessary?[ Go to top ]

    Java newbies struggle today with the distinction between static and non-static scopes. How do you expect them to cope with yet another abstraction and for what gain?

    Do people find that they get worn down from typing too much? You should change to a competent development environment instead of attacking the language semantics.
    Anonymous classes have such a non-intuitive syntax that I avoid getting newbies to learn it. I recently showed it to someone who has a year's learning behind him (and some enthusiasm) and it made sense, but I doubt it would to new starters. However, this means the newbies end up passing around a lot of context data from one object to another (typically in constructors). In other words, they are emulating the work that the compiler does in making anonymous classes happen (it generates extra constructor parameters, accessor methods etc.). If the anonymous class syntax was less obstructive, I'd be much happier teaching it. I don't really care about newbies all that much though - they'll still learn if they know how to learn. If newbies can cope with try blocks then they can cope with (simple) closures. E.g., try { stuff } is not much different to invokeLater { stuff }. About the 'competent development environment' bit: The problem is not related to typing, but reading. Anyway, which development environment works the best with anonymous classes, out of the box? In Eclipse, when I type Runnable runnable=, one of the options is a template for a Runnable anonymous class. But that's a hard-coded one, it doesn't work for arbitrary interfaces. IDEA doesn't do that. No idea about Netbeans. Neither Eclipse nor IDEA can refactor a named class to an anonymous class. Both IDEA and Eclipse plan to support a code-folding-like view of anonymous classes as closures; the code would still be an anonymous class but it would be easier on the eye.
  7. Re: Is this really necessary?[ Go to top ]

    Anonymous classes have such a non-intuitive syntax that I avoid getting newbies to learn it. I recently showed it to someone who has a year's learning behind him (and some enthusiasm) and it made sense, but I doubt it would to new starters.
    Seriously now, it doesnt take a year to get to the level where you understand anonymous classes. If it does, then the student should be advised to rethink his/hers career choice. Even it it is the students first language, learning all the language constructs should take no more than 8-10 weeks. Of course it takes longer to master all of the core API:s.
  8. Re: Is this really necessary?[ Go to top ]

    In Eclipse, when I type Runnable runnable=, one of the options is a template for a Runnable anonymous class. But that's a hard-coded one, it doesn't work for arbitrary interfaces. IDEA doesn't do that.
    Oh, it sure does. Type Runnable r = new and IDEA offers you all available classes (and interfaces) implementing Runnable (including Runnable itself) for implementation; whenever you choose an interface or abstract class from that list, it creates an anonymous class with stubs for all methods that need to be implemented: Runnable r = new Runnable() { public void run() { } }; And, of course, this is in no way hard-coded; it works for all interfaces and abstract classes.
  9. Re: Is this really necessary?[ Go to top ]

    Oh, it sure does. Type
    Runnable r = new
    and IDEA offers you all available classes (and interfaces) implementing Runnable
    Damn. I was using ctrl-space, not ctrl-shift-space. Thanks.
  10. Re: Is this really necessary?[ Go to top ]

    For now I don't teach anything that has closures (Perl and Java).
    For the record, Perl supports closures; see here, and also Mark Jason Dominus' book Higher Order Perl.
  11. method references[ Go to top ]

    I for one think that it's an abuse of the interface construct that I have to define a whole interface just to hand a reference to a method to another object. There should method types and method references instead.
  12. Re: method references[ Go to top ]

    I for one think that it's an abuse of the interface construct that I have to define a whole interface just to hand a reference to a method to another object.
    There should method types and method references instead.
    Or both. A method that takes one argument and returns a value could use a generic 'Function' type:
    interface Function { R run(T input); }
    This way, you get one interface for all one-arg methods. For two arguments, you could make a Function2 and it could extend Function,R>. Of course, as generics doesn't support a variable number of type parameters, this doesn't simply scale up, but then there aren't really that many methods with lots of parameters being written these days, hopefully. Of course, autoboxing a plain method reference to a Function would be possible, but I don't think that's in any current proposals.
  13. Why do we need this. What is so hard to understand about the first code extract. With modern IDE's which are able to automatically generate stub implementations of interfaces is it really necessary to accomodate programming constructs such as closures just because Ruby does???
    I have to agree with this. I've seen lots of threads when people supporting closures compare to... the character count of the inner-class alternative. I can extend my inner-class later, add methods, if it's necessary. Can easily refactor it and promote to an non-anonymous inner-class, or a public class. And all this *without* typing. So... what is the problem? Can't be typing, unless you are using something like Notepad. Are non-Java IDEs that bad? ----- Gustavo.
  14. "From the programmer's perspective, that's pretty much all there is to it: no new concepts to learn, just a more concise syntax for something they already do." This is untrue, there is the concept of the public local variable after that in the spec. I think the spec authors tried to make their proposal look simpler than it actually is. So finals will be accessible from the closure, including variables that are only defined once (so can be made implicitly final), and public locals can be accessed from the closure. I prefer the other syntax, because in its simplest form it is more elegant, e.g.: invokeLater{frame.setVisible(true);} It does look complicated with more advanced forms than that though.
  15. Re: Closures without Complexity[ Go to top ]

    Maybe the problem here is the example given, but I really don't see what this gains us. If I already know Java, the first example code is quite clear so I don't need the new syntax. If I don't know Java, I'm left wondering why in the second example the 'new' keyword is needed to create the MenuItem but not the Command. Congratulations, you've just invented a new pain point for anyone learning the language. And please don't hold up 'foreach' as an example because that is a classic case of "we want to introduce something new but we don't want a new keyword". If they had wanted to implement foreach properly they could have done it with a foreach keyword. That would have been ten times easier to learn for new programmers, cleaner and easier to read. But, no, they have this obsession with avoiding new keywords. Oh, apart from enum. That never caused anyone a problem because nobody ever called their Enumerations enum, did they? Bottom line: if you're going to do something, either do it properly or don't do it at all. Half-way bodged solutions that try to please everyone will end up pleasing no-one.
  16. Here's a case where it would be nice to see an implementation. Anybody know if Sun's license allows someone to hack up JavaC to add a feature and release it out into the wild? Then instead of having to go from proposal to standard, we could have any number of competing proposals (including those from the same person or group) duke it out (no pun intended) in the wild. Frankly, if they would have done this with some of the other "features", they would have been killed (as they ought to have been). Peace, Cameron Purdy Tangosol Coherence: The Java Data Grid
  17. Anybody know if Sun's license allows someone to hack up JavaC to add a feature and release it out into the wild?
    I've been suggesting a real plugin approach to javac a few times, but no body is really reacting to that (maybe I'm not famous enough.... hm, that probably is it ;-). Main reason is that multiple language extentions can used side by side (think for example of AspectJ and such a closure implementation). But also would make extending Java easier, and you can have extentions included like adding a JAR to your program.
  18. Is it just me...[ Go to top ]

    ... or do the changes from static Comparator reverseOrder(final Comparator cmp) { return new Comparator() { public int compare(T t1, T t2) { return cmp.compare(t2, t1); } }; }to static Comparator reverseOrder(Comparator cmp) { return Comparator(T t1, T t2){ return cmp.compare(t2, t1); }; }solely comprise of syntactic sugar like dropping important keywords (new) which would enhance the readability of the source code? I use the old way quite a lot and think there's nothing wrong with it. On the other hand, I would prefer this proposal a lot over the one provided by Bracha, Gafter, Gosling and von der Ahé, as it uses Java-like grammar and does not introduce a completely new structure of statements. But that may just be me. :-)
  19. Re: Closures without Complexity[ Go to top ]

    I understand why script-kiddies would like the new syntax, but the first example is much better for serious collaborative development. It is easier to read and maintain.
  20. Re: Closures without Complexity[ Go to top ]

    I like this proposal much, much more then original BGGA proposal. Also, as mentined, keeping 'new' keyword is not a big deal for typing and reading but improves on understanding what is realy happending under the hood.
  21. Re: Closures without Complexity[ Go to top ]

    Also, as mentined, keeping 'new' keyword is not a big deal for typing and reading but improves on understanding what is realy happending under the hood.
    After second tought, I agree with authors regarding removal of 'new' keyword :)
  22. Re: Closures without Complexity[ Go to top ]

    If you find that you really want to program in an environment that has proper support for closures you'd be much better off programming in Scheme. Wait! That doesn't mean you have chuck Java. SISC is a very, very nice implementation of Scheme for the JVM that seamlessly integrates with raw Java code. Check it out: http://sisc.sourceforge.net.
  23. In for a penny...[ Go to top ]

    For that matter, since we know the type of arg1 and the syntax depends on that type having one method to override, why not chuck the whole thing and do something like: MenuItem menuItem = new MenuItem("Foo", { Window.alert("Foo was chosen") }); For all the niceties that closures bring to your code (IMHO), I wonder if its worth it to hack it in to Java proper instead of just using something like Groovy, JRuby, or the afore mentioned Java Scheme implementation when you need to.
  24. Type inference[ Go to top ]

    For that matter, since we know the type of arg1 and the syntax depends on that type having one method to override, why not chuck the whole thing
    Agreed. I think closures need to work in tight conjunction with the type system to infer the type of the closure, including its arguments. If the types can't be inferred (using a simple set of rules), it's a compile time error. As far as syntax goes, I'd like to see something similar to Nice's anonymous methods, with the exception that argument types are inferred and that the argument declaration block be optional in the cases in which no arguments are used.
  25. Closures and Syntactic Sugar[ Go to top ]

    If you look at languages like Smalltalk and Lisp (especially Lisp) that make heavy use of closures, you'll notice that closures are not syntactic sugar but rather structures that allow the languages to have much simpler syntax. I think this is why I was personally originally turned off by closures. Because my first real exposure to them was in Ruby, and they just felt...strange. But then I started studying Smalltalk and then Lisp. In Smalltalk they just make sense and in Lisp it's hard to imagine anything different. IMHO, Ruby has too much syntax for closures to be natural. But I'll admit I've just played with Ruby (I didn't like it at all) so I'm not speaking from extensive experience. So I don't think closures belong in Java. Java is a very verbose language. I think that's a strength. The compiler performs very little magic in Java other than producing bytecode - which is what it is for. So while in Lisp and Smalltalk closures are avoiding compiler magic, closures in Java are introducing a ton of compiler magic. Compiler magic is confusing (see C++ for details), and I think should be used very judiscously.
  26. I like it[ Go to top ]

    I like it, but why not go all the way: MenuItem menuItem=new MenuItem("Foo", Window.alert("Foo was chosen")); and if it's an interface with more than one method: //parameter to Blah is Comparable new Blah( int compare(T o1, T o2){...} boolean equals(Object obj){...} )
  27. Groovy closures[ Go to top ]

    For comparison, here's the syntax for Groovy closures: http://groovy.codehaus.org/Closures
  28. Groovy closures[ Go to top ]

    I am not too informed about closures, but this is more like what I think would be generally useful. I have only played with Ruby briefly, but the blocks concept did grab my attention, because it seems to give you the power of the template pattern without the overhead of inheritance.
  29. Intuitive enough[ Go to top ]

    This looks like a good syntax. Though I don't understand why they just don't want to borrow groovy closure syntax.
  30. Are you bored?[ Go to top ]

    Bob Lee, Doug Lea, and Josh Bloch are you bored? There is a featured blog about singeltonitis - do you have the convulsive-find-something-new-to-create-a-hype-itis?
  31. Re: Are you bored?[ Go to top ]

    Bob Lee, Doug Lea, and Josh Bloch are you bored?

    There is a featured blog about singeltonitis - do you have the convulsive-find-something-new-to-create-a-hype-itis?
    Java hasn't yet enough rough edges to overtake C++ as the most complicated mainstream language. Joint effort is necessary to make it happen in the next release.
  32. Say goodbye to anonymous class[ Go to top ]

    glad to see Java finally catch up on this. The anonymous class syntax is just like a pile of sh*t compared to block in groovy/ruby and lambda in c#。 For such a long time, the disgusting and distractive anonymous class syntax has been intimidating away good style of programming in favor of inheritance oriented style. With closure introduced (assuming it is added right), programming in Java will be more fun and less painful. One question, why do they still require me to write new Command(int a, String b){...}? Does the compiler not able to automatically infer the parameter types?
  33. Give it up, Java[ Go to top ]

    Java is too verbose for closures. Regardless of what anyone comes up with in java, it will never beat expressions like sockets do: [:sock | sock isConnected ifTrue: [sock close]]. One line -- One line of code for that.
  34. Hi Bill, I like your littel Smalltalk example. I think the main reason why closures in Smalltalk, Lisp, Ruby, Groovy, etc. look so concise and simple is that no type information needs to be defined in the closure block. For languages that are statically typed all the type information that has to be carried along makes the closure harder to read and finding a simple syntax is not trivial. Nevertheless, I believe that closures in Java still makes sense, because the advantage of closures also make things a in Java lot simpler: inside the closure the outer scope is enclosed. So you don't have to pass on variables required inside some block of code as a final variable as with anonymous inner classes, create an additional method or class for simple things like iterations. The examples in this thread are in my opinion not that insightful as they use closures to solve problems for which access to the outer scope is not needed. This makes people believe that closures are only about syntactic sugar. Regards, Oliver
  35. syntax sugar[ Go to top ]

    The examples in this thread are in my opinion not that insightful as they use closures to solve problems for which access to the outer scope is not needed. This makes people believe that closures are only about syntactic sugar.
    That's exactly what I thought when reading this article. That this is nothing more than syntactic sugar. How about some more concrete examples that prove otherwise? I do find the "final" requirement annoying however... Thanks, Bill
  36. Re: syntax sugar[ Go to top ]

    I do find the "final" requirement annoying however...
    Haskell has closures, and technically, it doesn't have variables. Everything is implicitly final. In Java, this is not practical. You need variables (or emulated variables), at least for keeping track of looped calculations (recursion instead of looping is not practical, StackOverflowError anyone?). If you get into the habit of differentiating between variables that really need to be variable and those that don't, it can make code easier to read. If I see 'final int x=y+10;' then I can keep what 'x' means in my head and not worry about whether it will be assigned later. So, regardless of the anonymous class syntax, I'd suggest that you make your variables final by default (though final variable does seem an oxymoron). An upshot of the 'final' requirement is that it encourages anonymous class implementations not to change method-local state. IDEA has inspections for variables and parameters that could be made final, which helps. And if you implement an anonymous class that uses a non-final, IDEA and Eclipse both will prompt you to make the variable final. I do wish they'd have a setting to do that without asking though...
  37. Re: syntax sugar[ Go to top ]

    An upshot of the 'final' requirement is that it encourages anonymous class implementations not to change method-local state.
    They can neither access nor modify method-local state. It is impossible (outside of the debugging API) to access or modify some other method-local state. The various "final variables" that are referenced by the anonymous class end up (for example) being constructor parameters to the anonymous class, which is why the anonymous class instance will never see the value of those variables change. As a result, the language designers decided to force you to declare them final to avoid the question of "why don't I see when the variable changes?" Peace, Cameron Purdy Tangosol Coherence: Clustered Shared Memory for Java
  38. I hope it works out[ Go to top ]

    Hello Oliver, Well I hope it works out. I'm just skeptical of its success and see too much potential for more bloat in the syntax. With inner and anonymous classes, generics, autoboxing, etc., it seems like we're running into diminishing returns on our investment in these things. Cheers, Bill
  39. Little closure sample[ Go to top ]

    Hello, I tried to make up a simle sample of a closure that accesses a variable in the outer scope to point out why I find closures very powerful and elegant. First a sample without access to the outer scope: sockets do: [ :socket | socket isConnected ifTrue: [socket close]]. This is not that impressive as the Java equivalent is quite the same: for(Socket socket : sockets) { if(socket.isConnected()) socket.close(); } Now some Smalltalk code snippet with a closure accesing a variable in the outer scope: | number | number = 3. #( 1 2 3 ) collect: [ :each | each + number] ==> #( 4 5 6 ) Try to code this with Java. Note that number is assumed to be in the outer scope and not accessible from within the anyomous inner class. You end up having to write quite a bit of code for such a simple thing. One point is here that for only adding up a number to a list of numbers is so trivial you wouldn't create an anonymous inner class or create a new method. Ways too much code for such a simple thung and a solution with a method would have no potential for reuse. Closures are very usefull when you just want to say what should be done, and the real work is done in methods that are called. You could also solve the thing with conventional for loops. Once the expression in the closure block gets more complicated as in the sample above the solution with for loops will also hit some limit besides from being inelegant anyway. There are other good uses of closures of course such as implementing callbacks for GUI events. I should list many more now, I know. That's what people expect ... But this posting would become ways too long. I hope the little example above is somewhat hopeful. If Sun had implemented closures from the beginning there would be no problem with syntax bloat as there would not have been a need for anonymous inner classes, iterators would have been very simple as in Smalltalk and other things. Now the situation is somewhat screwed up. Probably, anonymous inner classes will stay in Java forever for the sake of backwards compatibility like the Pentium had to be backwards compatible to the 8088 for the sake of running old DOS boxes. When you come from a direction where closures were a common thing like classes and methods you simply can't believe how much code you have to write to get simple things done and you simply want your closures back. People that come from other directions tend to see the syntax bloat in Java as the eminent problem. Regards, Oliver
  40. Re: Little closure sample[ Go to top ]

    One point is here that for only adding up a number to a list of numbers is so trivial you wouldn't create an anonymous inner class or create a new method.
    Oliver, I totally disagree. In Java, a class is addressable (because an object is a reference), and theoretically a method could be likewise easily addressable (with a small amount of delegate -- oops, I meant delicate -- work from Sun). In Smalltalk, a "block" is addressable, and so you can use it for a closure. In Java, the smallest addressable block (in this case) is the method. The real problem is that the ClassFile format (as defined by the JVM specification) is file-based and monolithic, meaning that inner classes are way more "expensive" (in developers' minds) than they are in reality. Similarly methods, although much less so. (Java already has anonymous methods, and few people even know it. ;-) Peace, Cameron Purdy Tangosol Coherence: Clustered Shared Memory for Java
  41. closures[ Go to top ]

    "Therefore, we further propose allowing such access if the local variables in question are explicitly declared public" So how does that work in terms of objects being managed by the JVM then ??. Is an implicit object created to hold the values outside the lexical scope of the outer method ?. This would seem to be horribly bluring the distinction between things that are explicitly new'ed and local stack values. I agree with the posters who have said that there seems to be far to much "magic" going on here. By all means lets examine some possiblities for syntactic brevity BUT implicitly new'ing and creating hidden objects is going too far IMO. Isnt the problem here that we cant straighforwardly create an object, which serves effectively as the closure scope, and pass it as an argument to an inner class constructor ?. Yes that would be very verbose but cant we address the verbosity as a seperate problem in its own right instead of introducing all of these perl-esque context dependent hidden bits of magic. Paul C.
  42. My 2 cents[ Go to top ]

    http://www.digizenstudio.com/blog/2006/10/11/why-i-think-cice-is-more-complex-than-necessary/ Well, I guess the link gives it away...
  43. Lack of new ??[ Go to top ]

    I kinda like the idea, but, like Lars on the InfoQ thread, find the lack of 'new' disturbing.