Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Java finally getting closures, method handles and traits in JDK 8 (javarants.com)
48 points by spullara on Jan 23, 2011 | hide | past | favorite | 34 comments


Background: I started programming Java in 1996 or somewhere around there. I was a huge advocate of Java over things like C/C++ for quite a long time and I believe in early 2000 it was the best choice. I no longer believe Java is the best choice for most projects as there are saner alternatives out there including Scala, Clojure and Jruby (for the JVM) and other languages/VMs altogether if you want out of the JVM.

Bottom line: Java seems dated.

Now, to my rant.

import java.util.*; interface Sortable<T, U extends Comparable<? super U>> extends List<T> { void sortBy(Extractor<? super T, ? extends U> e) default Impl.sortBy; static class Impl { public static<T, U extends Comparable<? super U>> void sortBy(Sortable<T, U> sortable, final Extractor<? super T, ? extends U> e) { Collections.sort(sortable, #{T a, T b -> e.extract(a).compareTo(e.extract(b))}); } } }

I HATE this code. This is an example of when Java went downhill to me and started to get really, really ugly. I always thought Java was verbose, but with generics and others things it started to get ugly. That was enough for me. I knew Python and Ruby and decided to go a different way. Found Erlang and Clojure started to mature on the JVM. Bye bye Java.


Agreed.

I've been programming Java since the Alpha days and it is getting to the point where all the extended syntax is a bit outrageous.

The real problem is that most of these extensions are required to make Java more powerful, certainly generics / templating was a huge boon. But examples like the above make my eyes hurt.

I suppose my question is whether you can add all the features that make functional languages powerful while also retaining static typing. That's what Java is trying to do. In same cases the type safety is a huge boon to building a large system with many people working on it, in others something more dynamic allows you to be far more productive. I'm not sure you can have both and still have code anybody wants to write.

I haven't played much with Clojure yet, not sure if that is the best of both worlds.


> I suppose my question is whether you can add all the features that make functional languages powerful while also retaining static typing.

Of course you can. Look at Scala. (And on other platforms, F#, ML, and Haskell.)


I've read this criticism a lot, so I'm really curious:

How would you 'clean up' generics syntax in Java?


I've been writing Java for a while now. I've never seen nor written code anything like that. Heavy use of generics is usually hidden away in APIs and don't usually occur in non-trivial ways in normal code.


It's not that much of a hyperbole...

    Map<String, Map<String, Map<String, Map<String, String>>> > meta_data = new LinkedHashMap<String, Map<String, Map<String, Map<String, String>>> >();
    ....
    for (Map.Entry<String, Map<String, Map<String, Map<String, String>>> > schema : meta_data.entrySet()) {
I really would rather just type:

    meta_data = {}
    ....
    for schema in meta_data.iteritems():


This has become a bit simpler with Java 7: http://weblogs.java.net/blog/forax/archive/2009/08/27/diamon...

EDIT: link to better article


If you've got a structure like that, you've got bigger problems than the verbosity of the declarations!


Oh come on, it's not that ridiculous to have a map only 4 levels deep. (Though I'll admit the code there is a patch-job over a much worse design that will all be refactored one day...) It's just ridiculous to express in Java. JavaScript's pretty much built on the idea of nested objects/maps.

    new Ext.Panel({
        width: 400,
        height: 400,
        title: 'Pie Chart with Legend - Favorite Season',
        renderTo: 'container',
        items: {
            store: store,
            xtype: 'piechart',
            dataField: 'total',
            categoryField: 'season',
            //extra styles get applied to the chart defaults
            extraStyle:
            {
                legend:
                {
                    display: 'bottom',
                    padding: 5,
                    font:
                    {
                        family: 'Tahoma',
                        size: 13
                    }
                }
            }
        }
    });


That's fine. My point is, it's extremely uncommon to come across this kind of structure in Java-land. Typically, there'd be separate classes for these objects - so you'd end up with a Panel class with fields width, height, title, renderTo and items. Items would be another class with it's subsequent fields. And so on with no maps in sight.

You're example Java declaration doesn't seem to actually capture the Javascript code you've got there - ie each initial string does not map to another Map - in some cases it just maps to an integer or string.

By the way - I totally agree that the declarations of stuff in Java with generics is way too verbose.


You mean code that was interesting to write, and not just another fucking web template?


Java has had closures for years. Otherwise how would an anonymous inner class reference its parent's local variables?

I suspect the author is confusing closures (a language implementation technique) with anonymous functions (a language feature which can be implemented using closures).


While it's true that anonymous inner classes implement a form of closures, among the folks talking about the next version of Java, "closures" has become the shorthand for the various proposals to improve the syntax for callbacks and/or add true anonymous functions.


Do you mean method local variables? Because if so it doesn't - it copies them and only allows you to reference them if they're declared final (const) for exactly that reason.


There's a hack. Instead of declaring a local variable like "final double d = 4;", you can declare it "final double[] d = new double[] { 4 };" Then you can freely modify the 4 to something else inside the anonymous class. Why Sun didn't just bake that into the compiler instead of requiring a hack is beyond me.


That's exactly what a closure is.

Keep in mind that the concept of a closure has been bred in the functional programming community, where variables aren't mutable.

If you really need to reference a mutable variable in the enclosing scope, you can do in Java exactly what you can do in languages like ML/Scheme -- let the variable reference a mutable box (in Java, an object). The reference to the box (or object) is copied, not the box itself.

In fact, in Java you can go one step further and just reference the entire enclosing scope by storing the parent's "this" in a final variable.


Scheme has mutable variables, and introduced lexical closures in the 70's. You don't need any tricks with mutable boxes, you can just update an integer in the outer scope and it works fine. Scheme doesn't have an object system built in, but the closures make it easy to roll your own.


Java has had this since Java 1.1, I believe.


Yet another half-baked implentation of concept. Why in the world closures are limited to the SAM use case is beyond me. It's erasure all over again -- building a "general" purpose feature suited to one pratical use. It's no wonder that Java has lost its position as the platform on which to innovate and develop new projects. I wish Oracle would be willing to break backwards compatibility in JDK8, and deliver an truly innovative and exciting product. Guess I can wish for a visit from the Tooth Fairy too.

* I make my comments as a Java veteran, and fan of the platform.


Personally I feel the choice was a good one. Closures (& method handles) will work out of the box with virtually every API in the JDK along with a tremendous number of APIs generated by 3rd parties. The type inference / coercion rules makes them very easy to use and possibly not as limited as you imagine. In combination with extension methods interfaces can be updated to work even more smoothly with closures and method handles without breaking libraries that provide or depend on those interfaces. I'll gladly take specific feedback on use cases that you think have been dismissed by the current proposal back to the expert group.

Another question as I think they were unrelated. What kinds of features would you like to see in Java that would necessarily break backwards source compatibility? For example, I would like to see an 'auto' or 'var' keyword that is equivalent to the C++/Scala versions of same. Not a huge deal but would be nice.

Thanks!


The innovation on the Java platform is no longer in the Java language but in other languages on the platform. Both JVM-specific languages like Clojure and Scala as well as JVM implementations of existing languages like JRuby are where people go for innovation these days.


I definitely agree that Clojure, Scala, Groovy, JRuby etc are pushing the platform itself forward. InvokeDynamic is in JDK7 mostly for the benefit of dynamic languages on the VM and only in JDK8 will Java language features be dependent on it.


My understanding is that the vast majority of Java development is done in shops where conformance to coding and pattern "standards" is valued as a way of allegedly making the code base easier to read and understand (I am not agreeing with this, just stating what I believe they believe).

If my understanding is correct, which shop is going to allow people to start using these new techniques, when they already have a code base full of workarounds? Unless someone is going to sit down and refactor their humun-gi-normous code base, they will in effect be creating a second dialect of Java in their shop if they start using traits and closures instead of whatever they were already doing with Java's existing feature set.

I just can't see this having any more than a token impact. Now Java users can say, "Sure we have closures. We don't use them here, but they exist and if we wanted to, we could use them. But we don't need them, so it's no big deal."


Why wouldn't they use closures and other new stuff in Java? It's the same like it was with generics - prior to 1.5 we used raw types with casting, but when generics were introduced we started using them instead. When you encounter some older code in your codebase that still uses raw types instead of generics, you just rewrite that portion of code. No problem with that.

I mean, couldn't your point be made about any language that introduces new features? When that happens, do developers decide to rewrite the entire codebase? I don't think so.


Do you really rewrite working and tested code just to use new or more convenient features of the language? I don't see that being a good option, nor one that most developers would take.


If your code is covered with tests, why would you be afraid of rewriting it?


Hah!


You bet! Every chance I get. If I am in a section of code for some sort of change, I will definitely take the opportunity to update/improve the current state of affairs. Doesn't mean you need to go through and rewrite the entire thing.

For example, a recent requirement of mine was to revise some xml processing to create sitemaps. As part of the changes, I rewrote the logic to use xml LINQ (c#) and the resulting function is much cleaner, and will be easier to maintain going forward.

It also makes routine maintenance changes more palatable.


If the semantics are identical, you don't need to rewrite them, a good IDE will do that for you with a simple code reformat whenever you happen to be doing work in that file.


Well, you could use the same argument against any feature at all! Besides, I can point at zillions of Java applications that are not written by huge mystery corporations with legions of slaving programmers. There's no point holding back on improving a language just because you think some people might refuse to use your improvement.


I applaud your optimism and suspect we see things for ourselves in a similar light. However, every improvement of this sort added to a language is like a feature added to a product. It is not "free:" It increases the surface area of the language, requiring programmers to learn more to use it. Every "improvement" must be analyzed in light to whether the benefits outweigh the costs. My conjecture is that the costs will outweigh the benefits for the kilo-jillions of shops that are "mystery corporations with slaving programmers," as you put it.

As an aside, I think that the complexity of the language is already getting out of hand. Although features like this can be found in "little" languages like Javascript, they were in from the beginning and form part of the language's substrate. Libraries, frameworks, everything a Javascript user touches will make use of anonymous functions with lexical scope. More complex features are built on these features. This matters because when a programmer learns how a function works in Javascript, he learns how everything works.

Whereas when adding the same feature to Java, it's just being bolted on the side. So when a programmer learns how these new so-called closures work, all he learns is about a feature that isn't being used as a component of anything else, it's just a feature. We add complexity but get very little in return, much less than from the same feature in a language like Javascript.

I am not trying to get into a flame-fest over Java, but I do think that there comes a time when any product matures, and "improvements" should be viewed with extreme caution because the product has reached a point of greatly diminishing returns. I suggest that Java is in that place.


Undoubtedly, there will be maintenance projects that will develop this attitude, the places I've worked usually took a while to move to a new version, but once they moved they had no problem integrating the new features.

Essentially, this will replace the horrible callback syntax we have and have been using for a while. The new features will be integrated slowly, but they will be used.


I think the question here is whether or not it will defend against wholesale abandonment of Java to things like Scala and Clojure. To make the complete switch you might have to rewrite some code. With the Java improvements you can even keep a lot of your old code designed to work with inner classes and just use that code more effectively with the new closure and method handle syntax and implementation. There are many shops that probably haven't fully adopted generics from Java 5 in their own code but they benefit from the libraries that have moved to them.


Am I the only person who does not care very much about future features until they are tested and released? Many thanks to the people working on new JSRs but I'll wait.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: