Accessing non-final local variables from a lambda expression
Reinier Zwitserloot
reinier at zwitserloot.com
Fri Feb 26 05:26:30 PST 2010
Neal, this isn't a valid argument in favour of automatic heap allocation,
because you've just made a needlessly complicated example, skipping the
obvious way to do it with the new closure proposal. Here's yet another
alternative, which gets a little bit weird because AtomicBoolean has no
getAndFlip method, but the fact that your alternator could get away with
"return flag ^= foo;" was a lucky coincidence, and inline assignment is a
style most java shops don't allow in the first place.
<T> Iterable<T> everyOther(Iterable<T> input) {
AtomicBoolean flag = new AtomicBoolean();
return filter(input, #(T t) (return flag.getAndSet(!flag.get()));
}
or in a somewhat more verbose but easier to read fashion:
<T> Iterable<T> everyOther(Iterable<T> input) {
AtomicBoolean flag = new AtomicBoolean();
return filter(input, #(T t) {
boolean val = flag.get();
flag.set(!val);
return val;
});
}
Alternatively, with a keyword to move allocation to the heap, it becomes
much simpler still:
<T> Iterable<T> everyOther(Iterable<T> input) {
nonfinal boolean flag = true;
return filter(input, #(T t) (flag ^= true));
}
All of which look concise, and easy to read to me. They are easy to write
too, especially if the error message you get when you try it your way
explicitly points out the nonfinal / AtomicBoolean solution, which it
certainly can (and should!) do.
As a final point, your code isn't even "correct", in the sense that no java
shop in their right mind would let it pass. As you yourself said, it
generates a warning. Code shouldn't generate any warnings. We already have a
mechanism for turning warnings off, so we should use it here to be
consistent. Thus, your example would become, rewritten to the status quo
syntax:
<T> Iterable<T> everyOther(Iterable<T> input) {
@SuppressWarnings("heapallocation")
boolean flag = true;
return filter(input, (T t) (flag ^= true));
}
That's clearly inferior to the previous choice, and in my book still
inferior to the AtomicBoolean solution.
--Reinier Zwitserloot
On Fri, Feb 26, 2010 at 9:44 AM, Rémi Forax <forax at univ-mlv.fr> wrote:
> Le 26/02/2010 09:23, Lawrence Kesteloot a écrit :
> >> In BGGA, CfJ, and other languages with lambdas, one could write it
> >> simply like this
> >>
> >> <T> Iterable<T> everyOther(Iterable<T> input) {
> >> boolean flag = true;
> >> return filter(input, (T t)->(flag ^= true));
> >> }
> >>
> >> But project lambda forbids access to mutable local variables from the
> >> enclosing scope.
> >>
> > <T> Iterable<T> everyOther(Iterable<T> input) {
> > final boolean[] flag = new boolean[] { true };
> > return filter(input, (T t)->(flag[0] ^= true));
> > }
> >
> > It's not beautiful, but not the end of the world either. And the
> > performance is comparable, since in any case you have to create and
> > dereference some heap object.
> >
>
> +1
>
> > Lawrence
>
> Rémi
>
>
More information about the lambda-dev
mailing list