Lambdas in for-each loops

Kevin Bourrillion kevinb at google.com
Wed Sep 5 10:30:51 PDT 2012


On Wed, Sep 5, 2012 at 1:51 AM, Maurizio Cimadamore <
maurizio.cimadamore at oracle.com> wrote:

The for-each context is not straightforward - when the compiler sees:
>
> for (String s : exp)
>
> it doesn't exactly expects an Iterable<String>, as exp can be either an
> array or an Iterable.


To the user learning how to use lambdas, this should present no problem, as
an array obviously can't be seen as a functional interface type. This
"feels" no different from this case:

  void foo(Bar[] bars);
  void foo(Iterable<Bar> bars);
  foo(() -> qux);



> Howvere, even if we ruled out the array case, we still would have the
> problem that the variable declaration 's' corresponds to several potential
> target types (not just one) as there might be wildcards involved.


In

  for (Foo foo : () -> fooIterator) { ... }

Conceptually the context "expects" an Iterator<? extends Foo>. Again, I can
only comment on the user's perspective, not that of the spec writer etc. I
can't easily explain to a user why the above wouldn't work.


On Wed, Sep 5, 2012 at 4:29 AM, Maurizio Cimadamore <
maurizio.cimadamore at oracle.com> wrote:

I think the point is: is there enough value in the proposed feature (add
> lambda support in for-each loop) to justify this increase in complexity?
>

I wouldn't look at this as a conversation about a "proposed feature."  As a
feature, it's completely worthless. That's not the point.  The only point
is what makes the language changes seem simpler and easier to understand
for users.  Because I can guarantee they *will* try this, and they *will* be
completely surprised if it doesn't work.


If the main use case is to convert an existing iterator into an Iterable
> instance, it seems to me that we can achieve a very similar effect w/o
> any language modification and using an API-base approach:
>
> for (String s : Iterables.asIterable(it)) { ... }
>
> Which, with some static import magic can be reduced to:
>
> for (String s : asIterable(it)) { ... }
>

FWIW, Guava has rejected that method dozens of times, and will continue to
reject it for all time. For one, it's a pretty worthless "feature", as I
said above; for another, it produces a horribly-behaved iterable that the
user could do *anything* with.

In JDK 8, we sadly can't stop users from doing this:

  Iterable<String> badIterable = () -> stringIterator;

So we just have to accept that. But the irony is that we'd allow the bad
case (they have a Weird Iterable they could pass to anything, with
unpredictable results), but we wouldn't allow the safe case (the lambda
appears directly in foreach, so nothing can get a hold of it to cause any
harm).


More information about the lambda-dev mailing list