Twitter icon.
Random notes on software, programming and languages.
By Adrian Kuhn

Pimp my Foreach Loop


Java’s foreach loop is useful but limited. Neither can we access the iterator of a running loop, nor can we write Ruby-style1 foreach loops, such as

1) In fact, this style of looping can be traced back to the ancient times of legendary Smalltalk.

names = words.select { |each| each.frist.upcase? }     

bool = words.any? { |each| each.size > 7 }

length = words.inject(0) { |sum,each| sum + each.size }

We all know, this is because Java is – even though in its 6th release – still without the most basic structure of a programming language: Clo-clo-closures! (And rumours are, they wont fix that for the 7th release either.)

There are workarounds. Typically, anonymous inner-classes are (ab)used as closures. I dont like that. All the syntactic clutter and implementation overhead of using full-blown classes, only to inject some simple behavior into a loop? IMHO, not worth it.

Instead, here is a small DSL that pimps ye old Java foreach loop for you:

for (Select<String> each: select(words)) {
  each.yield = each.value.charAt(0).isUppercase();
}
Collection<String> names = $result();
for (AnySatisfy<String> each: anySatisfy(words)) {
  each.yield = each.value.length() > 7;
}
boolean bool = $result();
for (Inject<Integer,String> each: inject(0,words)) {
  each.yield += each.value.length();
}
int length = $result();

How does it work?

Behind the scenes, Java’s foreach loop operates on an instance of Iterable. Thus we can hook a custom object into the loop and get called back upon starting and terminating the loop, as well as before and after each iteration.

In the first example, #select is a static method that wraps the given collection in a custom object. The custom object is of type Iterable<Select>, where Select has two fields. One field is used a input parameter, the other as output parameter. Before each iteration of the loop, value is populated with the current element. After each iteration, yield is polled for a boolean value. Inbetween, the loop is executed.

While running the loop, all elements for which the loop yields true are copied into a new collection. Upon terminating the loop, this collection is assigned to $result. To keep things thread-safe, the result is stored in a ThreadLocal variable .

The same technique is used in the two other examples. #anySatisfy checks if all iterations of the loop yield true. #inject combines all elements by injecting an accumulator value into each iteration of the loop.

The list of currently supported queries includes

  • AllSatisfy
  • AnySatisfy
  • Cardinality
  • Collect
  • Count
  • CutPieces
  • Detect
  • Fold
  • GroupedBy
  • IndexOf
  • Inject
  • Reject
  • Select

If you need more, you can subclass For<Each,This<Each>> and implement your own query. As an example, I shall leave the implementation of Count here:

public class Count<Each> extends For<Each,Count<Each>> {
  public Each value;
  public boolean yield;
  private int count;
  protected void afterEach() {
    if (yield) count++;
  }
  protected Object afterLoop() {
    return count;
  }
  protected void beforeLoop() {
    count = 0;
  }
  protected void beforeEach(Each element) {
    value = element;
    yield = false;
  }
}

As usual, the complete sources are available on SCG subversion.

Have fun!

17 Responses to “Pimp my Foreach Loop”

  1. Rudolf Olah Says:

    One small correction: those Ruby-style foreach loops are in fact *Smalltalk*-style. This matters when you consider that Java came after Smalltalk and Ruby came after both.

  2. Bruno Borges Says:

    Hey Adrian, your hacks are really awesome.

    But there’s one thing that I’ve been trying to accomplish and until now, no success.

    I don’t even know if this is possible, but for what I’ve understood of how Roman Numbers were replaced, maybe you can figure out better (of course!) than me.

    Java doesn’t allow us to use Enums as values for Object[] or String[] of Annotations. For example:

    package com.some.auth.framwork;
    @interface AuthRoles {
        String[] values() default {};
    }
    
    package com.mycompany.security;
    public enum MyRoles {
        ADMIN, USER;
    }

    and then, something like this

    @AuthRoles(values={MyRoles.ADMIN, MyRoles.USER})
    class MyPojo {}

    Do you think this is possible somehow?

    Thanks! and good job!

  3. Bruno Borges Says:

    Oh, by the way… the reason I want to do this, is to have Enums instead of Strings for type-safety.

    And of course, this doesn’t work:

    @AuthRoles(values={MyRoles.ADMIN.name(), MyRoles.USER.name()})
    class MyPojo {}

    :-)

  4. Stephan Schmidt Says:

    @Rudolf: Java obviously came after Ruby.

    Peace
    -stephan

  5. akuhn Says:

    @Rudolf – you are so right! I’ve added a footnote promoting Smalltalk :)

    @Bruno – I’ll take a look, if its part of the AST (which I assume) there should be a way to rewrite it. I guess you would like to replace the enums with their string value.

  6. Stephan Schmidt Says:

    Sorry for my last comment, both are from 1995, I thought Ruby was older (as a kind of “successor” to Perl, therefor the name).

    Peace
    -stephan

    http://www.codemonkeyism.com

  7. SJS Says:

    FYI, “dont” isn’t a word — you might want to hire a proofreader.

    I find it astonishing that anyone would consider closures to be “the most basic structure of a programming language” — they’re nice, sometimes, but they’re hardly basic. Don’t confuse your personal preferences with fundamentals, it only serves to harm your credibility with those who don’t (<– that’s a real English word) share your prejudices.

    That being said, you have a slick idiom there. Emulating Smalltalk-style collection operations in Java with a minimum of syntax abuse is pretty cool.

    Wishing for closures in Java, however, seems dangerous. They’d probably screw it up like they did generics. That would be worse than anonymous inner classes.

  8. anonymous Says:

    SJS,
    For your information, “FYI” is not a word - you might want to hire a proofreader.

    Missing apostrophes are an abbreviation (as are three letter acronyms). In the same way, “don’t” is not a word either, but an abbreviation no doubt frowned upon by the slaves to language past who insisted instead on the correct usage of full “do not”.

  9. Caligula Says:

    @SJS:

    A missed apostrophe, in a non-native language, is hardly worthy of a snarky proofreading comment.

    Are you truly *astonished* at the characterization? Did you gasp out loud? At *best* I was mildly intrigued at the characterization, although I do feel they’re at least *a* pretty basic technique.

    I think, perhaps, you’re too comfortable with hyperbole and nit-picking.

  10. Casper Bang Says:

    @Adrian: Way to emulate yield in Java. ;) It’s a little silly we need to mess with ThreadLocal for something that should be in the language but I guess that is the Java way of things.

    @Bruno: Are you doing Wicket development? Looks like it. Indeed you can use Enum’s, but not in place of an Class. Imagine you could, what would the difference be between MyRoles.USER.name() and MyRoles.ADMIN.name()? None, both resolve to the same Enum class. Why don’t you just retrofit/overload it so that you can use Enum instead?

  11. henk Says:

    Pretty nice. The trick with $result(); and TLS is pretty clever, although purely syntax wise I like this the least. It feels a lot like these old C functions for getting an error code.

    Although the trick is really clever, perhaps something like the fragment below would be more closer to what Java developers expect?

    Select select = select(words);
    for (Select each: select) {
      each.yield = each.value.charAt(0).isUppercase();
    }
    Collection names = select.result;
  12. Itay Maman Says:

    Adrian,

    I think it is a clever approach to a thorny issue. Like it a lot. I bet you will get criticism from FP/Rub/Smalltalk people saying that Java sucks and that it should have supported this and that. This may be true, but still you managed to find a good practical solution to a real problem.

  13. Mircea Says:

    hehe, nice idea :)

  14. Chris Wash Says:

    Awesome idea - Impressive enough to warrant an RSS and Follow on Twitter.

    I saw this attempted here as well, but you’re limited to using the Hamcrest matchers: http://code.google.com/p/hamcrest-collections/wiki/GettingStarted

  15. akuhn Says:

    @henk – now it can be done, checkout the latest revision.

    Select<String> selection = Select.from( words );
    for (Select<String> each: selection) {
        each.yield = each.element.charAt(0).isUppercase();
    }
    Collection<String> names = selection.result();
    
  16. Eugene Lucash Says:

    I definitely support such kind of experiments!
    But just compare

    Select selection = Select.from( words );
    for (Select each: selection) {
        each.yield = each.element.charAt(0).isUppercase();
    }
    Collection names = selection.result();
    

    Vs

    Collection names = new ArrayList();
    for (String word : words) {
        if (Character.isUpperCase(word.charAt(0)))
            names.add(word);
    }
    

    Idiomatic java looks not that bad in comparison

  17. akuhn Says:

    @Eugene – I agree, idiomatic java does a good job for simple queries. It is when queries get complex that the DSL starts to pay off. That is, either for queries such as GroupedBy and PiecesCut with a complex internal logic, or for query whose loop body is more than a few lines long.

    A main strength of the DSL is that it is intention revealing. “Say what you do, not how you do it.” Scanning code for uses of Select is much faster then deciphering an idiomatic construct. Even worse, any slight variation in the combination of for’s and if’s might turn your select idiom into a reject, or select or detect instead. Thus, I personally prefer the DSL for trivial cases even.

    And now, installing lambda4jdt … looks wow!

For.example is Digg proof thanks to caching by WP Super Cache!