Path: csiph.com!v102.xanadu-bbs.net!xanadu-bbs.net!feeder.erje.net!us.feeder.erje.net!news2.arglkargh.de!news.swapon.de!fu-berlin.de!uni-berlin.de!individual.net!not-for-mail From: Robert Klemme Newsgroups: comp.lang.java.programmer Subject: Re: Why is that in JDK8: value used in lambda expression shuld be effectively final? Date: Mon, 07 Jan 2013 23:08:24 +0100 Lines: 76 Message-ID: References: Mime-Version: 1.0 Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Trace: individual.net J4ouD4mpIcEG85PR30bGtAJQ62ivgcxid9aVNpIH4okV9zhnEbDWryY3QWd5iIA6I= Cancel-Lock: sha1:wQiasd5RYfJZ8yGBNtnJTxtrK2k= User-Agent: Mozilla/5.0 (Windows NT 6.0; WOW64; rv:17.0) Gecko/17.0 Thunderbird/17.0 In-Reply-To: Xref: csiph.com comp.lang.java.programmer:21169 On 02.01.2013 15:15, Steven Simpson wrote: > On 02/01/13 12:51, jeti789@web.de wrote: >> I'm currently plaing with JDK8 and using >> lambda-8-b69-windows-i586-17_dec_2012. I wonder why this does not >> compile: >> >> List ints = new ArrayList<>(); >> ints.add(1); >> ints.add(2); >> ints.add(3); >> >> int sum = 0; >> ints.forEach(i -> {sum += i;}); >> >> The compiler error is "value used in lambda expression shuld be >> effectively final" > > It's the same reason why inner classes can't mutate local variables in > the enclosing scope. The method that accepts the lambda or inner class > instance cannot formally make any guarantee not to invoke the supplied > code in a non-serial way. I don't think concurrency is the main reason. It has more to do with the complexity involved in keeping the surrounding scope (local variables on the stack) alive for an _indefinite amount of time after the invocation of a method_. For mutations of references or POD values in the surrounding scope this scope would need to stay around for as long as the inner / anonymous class instance lives. In this case public Runnable sample(int count) { return new Runnable() { public void run() { while ( count > 0 ) { --count; } } }; } variable "count" would need to be assignable at least as long as the created instance lives. Same for any local variable declared inside the method body. If it weren't we would not have proper closure semantics (e.g. when returning two instances which refer the same variable from the scope). Since the scope need to be kept for longer, it cannot reside on the stack. That would introduce two different ways of local variable access: one via the stack and one via some reference on the heap. I guess since variable access is such a fundamental feature language designers did not want to introduce this type of complexity. (There could also be performance issues lurking.) With "final" variables it's easy: just copy all used values or references in hidden member variables of the created instance and be done. Because original variables are final the scope does not need to be kept around: since state of variables in the scope cannot change both values cannot digress. And actually this is what is happening, as you can see when disassembling code. Example at github because the disassembly output is quite long. https://gist.github.com/4478864 The member is declared in line 140 and the constructor in 146. Also you can see that the value of this field is used in line 195. This does not change in Java 8 because compatibility with old code was intended. lambdas are merely syntactic sugar for "old" Java features. For anyone interested in the details I recommend to read http://cr.openjdk.java.net/~briangoetz/lambda/collections-overview.html Kind regards robert -- remember.guy do |as, often| as.you_can - without end http://blog.rubybestpractices.com/