Why Java Needs Closures

There was a post by Bruce Eckel on Artima  this week that asked the question of whether or not closures would make Java less verbose, so it seemed like an apt time to put this up.

People tout closures as cure-alls for all sorts of things:  because they like functional programming or because it’s better suited to certain tasks, or maybe because they want to use it for control structures (so they don’t forget to close a file after reading it, say).  Honestly, I’m just sick of writing this same block of code over and over again:

Map<User, List<Claim>> claimsByUser = new HashMap<User, List<Claim>>();

for (Claim claim : someListOfClaims) {
  List<Claim> claims = someListOfClaims.get(claim.getUser());
  if (claims == null) {
    claims = new ArrayList<Claim>();
    claimsByUser.put(claim.getUser(), claims);
  }
  claimsByUser.put(claim.getUser())
}

I’d much rather write something like:

var claimsByUser = someListOfClaims.partition(\claim-> claim.User)

Sometimes I feel like all my Java code devolves into a morass of for loops and angle brackets (I like generics, mostly, but without type inference they’re exceedingly painful). Even worse, it’s the same few for loops over and over again. You can write helper classes and methods to do things, and you can simulate closures using anonymous inner classes, but even then your code looks like:

Map<User, List<Claim>> claimsByUser = ListUtils.partition(someListOfClaims, new Partitioner<Claim, User>() {
  public User partition(Claim c) {
    return c.getUser();
  }
});

Hardly the most elegant code on the planet.  If you had to read or modify the code, hopefully it’s obvious which one is easier to understand and easier to change.

There have been multiple closure proposals floated for inclusion in Java 7, and the one that looks like it’ll make it in is, like the generics implementation, a bit too complicated in the wrong ways. The arguments over exception and return handling within closures, along with debates about the scoping rules, have not (in my opinion) ended well, mainly (from what I can tell) due to a desire to be able to use closures to allow programmers to create new language-level control constructs, like the for loop added in Java 1.5. From my viewpoint, they’re silly questions to ask in the first place: a closure is a function, so a return statement within a closure just returns from that function. Returning from the containing scope just seems like madness and an invitation to serious confusion. Yes, it lets you define new control structures, and yes, new control structures can also simplify code, but I really think they should be two completely different features. Keep closures simple and understandable, with simple, consistent rules about scoping, return values, and exception handling. If people still demand better control structures, then make that a separate effort and implement those cleanly and simply.

While nothing’s been officially decided yet, I’m guessing that the two most likely outcomes are either 1) a confusing, over-engineered closures implementation or 2) no closures at all. And that’s just unfortunate; even some simple form of closures allows for a major simplification of routine data structure manipulations that both reduces code and makes code more clear.  And of course, closures are far more concise and usable if you add type inference in as well, but that’s another post. Just yet another reason why the world needs a language like GScript.


8 Comments on “Why Java Needs Closures”

  1. jag says:

    You seem to have made some mistakes in the example of the code you’d rather not write over and over, which actually neatly makes a case for why you’d want to avoid writing it over and over (though your compiler would’ve pointed out the mistakes):

    for (Claim claim : someListOfClaims) {
    – List claims = someListOfClaims.get(claim.getUser());
    + List claims = claimsByUser.get(claim.getUser());
    if (claims == null) {
    claims = new ArrayList();
    claimsByUser.put(claim.getUser(), claims);
    }
    – claimsByUser.put(claim.getUser())
    + claims.add(claim);
    }

  2. Mike says:

    Personally, I prefer the more verbose code. It is very easy to read and work on. The code using closures just seems like voodoo.

    Closures are a bad idea, and I hope they are not part of Java 7 (just like generics should not have been part of Java 5).

  3. Alan Keefer says:

    jag, thanks for pointing that out. I just wrote the code directly into the post rather than trying it out or copying it from anywhere, and clearly I should have been more careful. As you say, it just kind of goes to show that more code == more opportunities for errors.

    Mike, you’re certainly entitled to your own opinion, but in my experience they only seem like voodoo until you start using them routinely. Once you’re used to them, they actually make the code much easier to read. In the for loop case, you have to read the code carefully to figure out what it’s doing, whereas in the closures case the fact that you’re calling a well-named method (“partition”) makes it clearer what the intention of the code was.

    As I’ve accidentally demonstrated, it’s also pretty easy to screw up the Java version, and since the intention isn’t so clear it might also take someone longer to figure out what the code should have been. The closures version in this case is nearly impossible to screw up.

  4. Carson Gross says:

    Mike,

    Closures are like novocain: just give ’em time.

    OTOH, after the generics debacle in 1.5 I can’t really blame you for fearing what sun has in store for us in 1.7.

    Cheers,
    Carson

  5. peter lawrey says:

    You can write helper methods which do most of what you want which will remove the boiler plate code if you have to repeat this.

    However, I think closures would be more elegant.

    List claims = ….
    // group by just the User.
    List<List> claims2 = groupBy(claims, “user”);
    or
    Map<User, List> claimsMap = indexBy(claims, “user”);

    // group by the user and the age.
    List<List> claims3 = groupBy(claims, “user”, “age”);

  6. Carson Gross says:

    Peter,

    That’s a silly argument. You are using strings to program. In java.

    You know it’s silly.

    Trust me that Keef has tried every possible bat-shit crazy reflective way to make java more concise. They all suck. The right thing is closures.

    Cheers,
    Carson

  7. peter lawrey says:

    Silly it may be, but its concise and it works in Java 5. Using strings is nothing special, even in Java.
    Actually the method generates an anonymous class to access the fields. (and caches it) And a class to hold the fields efficiently. Closures could do both without a library to support them (or more accurately the library would be in standard java)

    Closures are useful when they make the problem read more naturally than the alternatives. I don’t think closures are the right solution to every problem.

  8. Alan Keefer says:

    Agreed . . . they’re just one of a number of tools. But they can often make simple problems simple, whereas in Java simple problems become just slightly less simple than they should be. There are certainly cases where the problem isn’t simple and where it’s thus more important to deconstruct it correctly, and places where using closures is overkill or makes things more complicated instead of less.

    I don’t think you’re really making this argument, but I have argued on a few occasions with people who insist that closures aren’t important because you can always do X in Java, and if you just write a helper method that does X it ends up exactly as elegant. So I could write a method called partitionClaimsByUser() and just call that; even better, I could just parameterize it a bit and write my own partition implementation complete with reflection and/or static constants for Partitioner implementations that I can re-use. And since that would be more reusable, it’s obviously a better alternative, right?

    It’s not exclusive to the Java community either; basically anyone, when their language of choice is criticized, seems to naturally respond with, “So, I can still do that in my language” and/or “It’s better that it’s hard to do X because you shouldn’t do it.” You have to type “self” all over the place in Python? It’s a feature, not a bug, since it forcibly beats you over the head with the scoping, and you’re supposed to like that beating. No unicode support in Ruby? Yeah, but there are external libraries for that. No packaging structure in Javascript? If you’re clever enough you can kind of fake it.

    And really, how can you win those arguments? If you’re arguing with someone who only cares about “can you do X” and not “how hard is it to do X,” well yeah . . . you can basically do anything in any Turing-complete language if you try hard enough, so what’s there to argue over?

    Our point is that it matters how you do things, and that little things add up: if you have to write 10 3-line helpers in Java to encapsulate that sort of nastiness, or even one 10-line helper that does magic reflective stuff, it’s a net loss versus just not having to write those lines in the first place because you can inline the code just as clearly using a closure.

    So again, I don’t think you were making that argument, but I hear it often enough that I figured it was worth clarifying. And closures really are only useful in specific circumstances, but not having them leads to more verbose Java code than would otherwise be necessary, and all other things being equal more code == worse.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s