Jörn has posted 4 posts at DZone. View Full User Profile

Closures in Java and Scala

05.21.2008
| 10818 views |
  • submit to reddit

People argue that verbose code is easier to understand. Do you agree when reading these two examples, one method in Java, one in Scala?

public List<Item> bought(User user) {
List<Item> result = new ArrayList();
for (Item item : currentItems) {
if (user.bought(item)) {
result.add(item);
}
}
return result;
}
def bought(user: User) = items.filter(user bought _)

If you are familiar with Java, which is more likely then you being familiar with Scala, you may tend to the Java-version. Scala has a different syntax for declaring types and generics, and supports closures, including anonymous parameters (the underscore).

When Closures are introduced in one of the next Java releases, JDK 7 or 8, the example could be rewritten like this:

public List<Item> bought(User user) {
return ListUtils.filter(Item item : items) {
user.bought(item);
}
}

Or with extension methods:

public List<Item> bought(User user) {    
return items.filter(Item item :) { // note the smily! thats what its all about!
user.bought(item);
}
}

And without the curly braces:

public List<Item> bought(User user) {    
return items.filter(Item item :) user.bought(item);
}
The interesting differences between Java with closures and Scala is the static typing: Scala inferences that items are all of type Item, so there is no need to specify that information again. Especially the last example shows that quite clearly.

So, while the current Java Closures specification is a great step in the right direction, lead by Neil Gafter, who is quite the right man for the job, it may not be worth to wait for it, if you have the choice. Its not even sure yet that we'll see that spec implemented in JDK7, and even that is at best one and a half year away.
Published at DZone with permission of its author, Jörn Zaefferer.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Honey Monster replied on Wed, 2008/05/21 - 1:04pm

I think your example may be a little too simplistic; you would probably not define a method just for this purpose as it would be just as easy and readable to filter on the Items property directly. This is at least true for your Scala example.

In my opinion the current BGGA proposal is skewed by the desire to allow for automatic resource management like the C# using statement. While it would be nice to be able to make such language enhancements yourself, I feel that closures are not the way to obtain it. That desire is responsible for the return problem (very well highlighted by your example) which makes code inside the closure block follow strangely different (non-Java-more-Ruby-like) semantics.

It would make more sense to keep closures simple and then perhaps include some kind of programmable syntax macros, which could allow for simplification of much boilerplate code.

BTW, the C# version of the method would be:

IEnumerable<Item> Bought(User user) {
    return items.Where(user.bought);
}

again, in this particular simple example you would just do

Items.Where(user.bought);

 

Osvaldo Doederlein replied on Wed, 2008/05/21 - 1:47pm

These arguments about which code is easier to understand are always biased towards whatever language one is familar with. I'll admit that the quality of a language's syntax design makes its code objectively more intuitive, but it's very hard to judge which factors are objective vs. subjective, unless you have extensive experience in all languages compared. For example, I have used both C++ and Java for many years, I'm a vet in both languages - so I consider myself prepared to pontificate about the relative merits of these two languages. OTOH, right now I'm just learning Scala (very slowly: no time), and I still read Java code much faster than Scala but I don't think this means anything - yet. In particular, functional programming techniques like higher order functions is a well-known point of dispute: everybody who have no real experience with FP is totally confused by code that relies even moderately on this feature, while every seasoned FP programmer (not my case) claims that once you 'internalize' this stuff to your mind, it makes code incredibly easier to both write and read.

Dmitriy Setrakyan replied on Wed, 2008/05/21 - 5:48pm

Funny thing. Remove the curly braces from Java closures example and the code in Scala is no longer "shorter". One could of course argue if curly braces hurt readability or not. But to me, they are much more readable than that underscore before the closing parenthesis in Scala example.

I do agree that Java could significantly improve with type inference though, especially for generics.

Best
Dmitriy Setrakyan
GridGain - Grid Computing Made Simple

Jeroen Wenting replied on Thu, 2008/05/22 - 3:46am

Let me quote Josh Bloch when asked about closures by DZone:

"Sugrue: What is your opinion on the inclusion Closures in Java 7?

Bloch: As readers of the first edition know, I value simplicity and clarity above all else. So it should come as no surprise that I don't want to see anymore major additions to the Java programming language. It's already as complex as a language should be. If Java programmers want to use features that aren't present in the language, I think they're probably best off using another langauge that targets the JVM, such a Scala and Groovy."

Couldn't agree more.

Jörn Zaefferer replied on Thu, 2008/05/22 - 3:50am

Thanks everyone for their comments!

Uffe Seerup: Of course the example is contrived, but thats always the case for examples. Just imagine an additional guard clause in front of the filtering and use that in more that one place - that should be enough of a reason to extract a method.

I'm not too familiar with the details of the BGGA proposal, but according to the presentation Neil Gafter gave on it, its not about resource managment ala using, but rather about control abstractions. Control abstractions would allow a library to implement using, instead of having to add that to the language itself.

Thanks for the C# example.

Osvaldo Doederlein: You could just consider closures as a simplification of anonymous classes.

I'm currently writing a Java web application on top of the Wicket framework. A simplification of anonymous classes would simplify my Wicket components a ton. I'd be happy to delete all that boilerplate code and let the compiler do some more work.

Dmitriy Setrakyan: Good point - I've updated the example accordingly. Now its even more clear that Java + Closures + Type Inference would get as quite close to Scala syntax in that case.

Jörn Zaefferer replied on Thu, 2008/05/22 - 3:56am

Jeroen Wenting: A major showstopper for using Scala today is the state of tool support. Hyperlinking of code elements, code completion, integration of API documentation, automated refactorings - all that stuff make me much more productive as a programmer. If closures were added to Java, I could leverage that without losing any of the benefits tools provide. Most likely Eclipse would have some additional helper for closures in its next version, too.

The current beta Scala plugin has hyperlinking and completion working, but is otherwise very unstable. I'm looking forward to the point where is actually usable.

Honey Monster replied on Thu, 2008/05/22 - 10:03am

joern: The point I was trying to get across (poorly) is that your example is perfectly reasonable in case of Java, but in the case of Scala and indeed any other mainstream language (Ruby, Python, Groovy, C# and even Visual Basic.NET) you would never write the corresponding method in the first place.

In Java you would indeed often choose to code a method for "items bought by user", as coding a loop inline takes away from readability. Loops are not as much read as they must be understood. Thus loops interrupt the reading of code and blurs the main purpose. That is why we like to abstract away loops like yours above.

But for languages that feature list comprehensions you would typically not write such abstractions in the first place, as they introduce an unnessecary level of complexity (you must now read the method to make sure it does what you believe). You would simply use the items list/collection inline with its list comprehension methods. There's no loop to understand.

Therefore closure support hold the potential to drastically cut down on goo code. I believe your example is perfectly viable, but in my opinion you should contrast the Java example with writing no method at all in Scala - and still retain on-par (or better) readability and more flexibility (more predicates than bought can be used).

To complete the example you could show the code where the methods are being used. That would make it more clear that using a closure indeed can increase readability.

 

Jeroen Wenting replied on Fri, 2008/05/23 - 12:54am

I was talking about the idiocy of introducing closures in Java, not about Scala (of which I have little knowledge, and which was I think designed with them in mind).

Closures (a.k.a. OO function pointers) are something that should be designed into a language from the ground up if you really want it, not retrofitted at some later point (say after 12 years...) to stroke the vanity of some people who like to see their name on a JSR.

Jess Holle replied on Fri, 2008/05/23 - 6:30am

I have to say I much prefer the Java example here, despite liking closures overall -- you can tell what's going on.

That said, a much better comparison would be with:

  1. public List<Item> bought(final User user) {  
  2.     return ListUtils.filter( items,
  3.                                   new AcceptFilter() {
  4.                                      public boolean accept(Item item) {
  5.                                        return user.bought(item);
  6.                                      }
  7.                                   }
  8.     );
  9. }
which can obviously be indented all sorts of ways.  If one ends up needing to create filtered sublists a fair amount the original Java code will be painfully redundant, whereas if it is used once (as in this article), then it is fine.  Otherwise the correct comparison is between ListUtils.filter with and without closures.

Jeroen Wenting replied on Tue, 2008/05/27 - 12:46am

and which isn't using closures (aka function pointers) but passing a class instance of an anonymous class. Java's supported that from the very beginning.
If it were closures you'd pass just the method as an argument, not the class it comes from. And that would be far harder to read and especially debug.

Eugene Kirpichov replied on Thu, 2008/07/03 - 3:23pm

I recently wrote an article that adresses the issues of readability of functional programs in java; you might have a look at it here: http://community.livejournal.com/jkff_en/341.html 

One of the issues it addresses is exactly about refactoring code like the snippet above, with new AcceptFilter(), for readability and modularity.

Jenny Floz replied on Thu, 2012/03/29 - 3:11am

Me too, I wanted to know the facts about java and scala. Thank you so much for sharing this one. it is indeed very helpful. - Claire Meks

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.