Effectively final

Brian Goetz brian.goetz at oracle.com
Sat Jul 30 09:18:07 PDT 2011


Reading between the lines, what Neal and I are both saying is: from 
where we are now, adding support for mutable local capture in lambdas is 
nowhere near our highest language priority.

On 7/29/2011 4:39 PM, Neal Gafter wrote:
> Asynchronous support can be much more usable when supported more
> directly by the language.  But until the language does provide that
> support you are forced to do it in a less expressive way using
> libraries.  It is true that mutable locals make that less onerous.  And
> I personally prefer that lambdas are usable to organize sequential code
> as well as concurrent code (remember, method bodies are always
> sequential today), which may require mutable locals in a language like
> Java.  But on the other hand I believe it is better to provide more
> direct language support for asynchronous rather then doing it through
> libraries, and that reduces asynchronous as a motivation for having
> mutable locals in lambdas.
>
> Cheers,
> Neal
>
> On Friday, July 29, 2011, Tim Fox <timvolpe at gmail.com
> <mailto:timvolpe at gmail.com>> wrote:
>  > Brian,
>  >
>  > Thanks for your reply. Comments below
>  >
>  > On 29/07/2011 19:08, Brian Goetz wrote:
>  >> You are right to have these concerns.
>  >>
>  >> The canonical example is:
>  >>
>  >> int fooSum = 0;
>  >> list.forEach(#{ x -> sum += x.getFoo() });
>  >>
>  >> You are correct that there are purely sequential use cases that
>  >> benefit from this approach, which are not subject to data races.  (On
>  >> the other hand, it is nearly impossible to write the above
>  >> primitive-using code so that it is not subject to data races in a
>  >> parallel environment.)  We have explored approaches of capturing this
>  >> constraint in the language, so that we could prevent or detect when
>  >> such a "thread-confined" lambda is used from the wrong thread.  While
>  >> these are likely feasible, they add complexity.
>  >>
>  >> Examples like the above have been around for 50+ years.  However, it
>  >> is worth noting that they became popular in the context of a
>  >> sequential, uni-processor world.  Rather than expend energy and
>  >> introduce additional complexity to prop up an aging and increasingly
>  >> irrelevant programming idiom,
>  > I'd have to disagree that this approach is aging, the success of node.js
>  > and ruby event machine are good counter-examples. They both use the
>  > reactor pattern (i.e. a single event loop which executes everything), so
>  > the developer does not have to worry about concurrency concerns. This is
>  > a huge win in terms of simplicity for the developer.
>  >
>  > Frameworks like node and eventmachine scale over cores by spinning up
>  > more processes, not threads (since there's only one event loop per
>  > process). This is less than ideal when you want to share state between
>  > event loops.
>  >
>  > New frameworks like node.x https://github.com/purplefox/node.x (which is
>  > what I am working on) allow multiple event loops per process (typically
>  > one event loop per core), and then partition objects so they are "owned"
>  > by one of the event loops. The framework will then guarantee that all
>  > callbacks on those objects are always executed by the same event loop.
>  >
>  > What you get out of this is the user can write all their code as single
>  > threaded, but the system as a whole scales well over available cores
>  > without having to spin up more processes.
>  >
>  > If the framework can guarantee this code is always executed by the same
>  > thread, it seems wrong to force users to use AtomicReferences (or
>  > whatever) to co-ordinate results from different callbacks.
>  >> we instead are directing our energies towards providing more modern,
>  >> parallel-friendly idioms, like:
>  >>
>  >>   int fooSum = list.reduce(0, Reducers.INT_SUM);
>  >>
>  >> which is more compact, more readable (once you learn what "reduce"
>  >> means), less error-prone, and can be parallelized by the library.
>  >>
>  >> You state that "most languages that support closures do allow capture
>  >> of mutable local variables."  However, most of them have
>  >> {little,no,bad} support for safe concurrency or parallelism.  If Java
>  >> were a strictly sequential language, the story might be different, but
>  >> that isn't the reality -- or desirable.
>  >>
>  >> We had three basic choices here:
>  >>  1.  Allow arbitrary mutable capture, and leave it to the user to not
>  >> create data races.
>  >>  2.  Complicate the language further by introducing a notion of
>  >> thread-confined lambdas, and allow mutable local capture by
>  >> thread-confined lambdas.
>  >>  3.  Prohibit mutable local capture entirely.
>  >>
>  >> To do (1) in 2011 would be foolish;
>  > I agree that 3) should be the default, since most people won't be using
>  > frameworks that guarantee access is always by the same thread. But I
>  > think it would be great if 2) was an option for those frameworks (and I
>  > think they will be a growing trend) which would benefit from a simpler
>  > programming style that it would allow.
>  >
>  >
>  >


More information about the lambda-dev mailing list