For example, in Java, lambdas cannot capture mutable variables from the outer scope - it must be final, or effectively final. C# always let you do that, from the very first implementation of lambdas.
C# lets you do that because C# doesn't have a way to declare a local readonly/final variable at all. I significantly prefer features that encourage the use of `final` variables everywhere that it is possible in Java.
I write C#, Java, and Kotlin in roughly equal measure. Each has its pluses. But the claim that Java's lambdas are worse because it doesn't let you--and this was a conscious design choice!--do something so potentially catastrophic and difficult to debug is an odd one.
I rather be able to do something than be prevented because someone somewhere thinks that it's "potentially catastrophic". That seems especially hyperbolic in this case.
Do Java programmers find mutable variables in general horrifying? That was not my impression - certainly, the language doesn't make it easy to make everything immutable. If so, why the special distinction for lambdas?
The official rationale was that they expected lambdas to be mostly used for parallel sequence processing, and wanted to avoid race conditions. Of course, in practice, lambdas are very useful in many other places, where there's no concurrency issue at all - async continuation callbacks, for example, or pseudo-custom language constructs implemented as functions with a lambda for a body.
The same memory model as any other shared variable being mutated by multiple threads - you either explicitly synchronize, or you just don't do it. But given that lambdas are far from the only way to get there - and those other ways are already idiomatic in the language (e.g. statics) - why single out lambdas specifically for this?
The ideal solution is to make this a part of the function type - so that APIs that do intend to invoke lambdas concurrently can mark them as such, and then the language would enforce sharing, while other APIs that do not use lambdas in a concurrent context, can use their full power.
Same thing goes for lambdas that cannot escape vs those that can - if you reflect this in the type system, then you can also support safe nonlocal breaks and returns in the former, for example. One of the early Java lambda proposals, the one by Neal Gafter, did just that, and it was awesome.
Yea, that seems frightening. I like to think of my local variables as my inaccessible local state. I'd imagine it keeps my JIT happy too. What would it even mean to have a lambda reference to a variable who's stack frame has already popped?
> What would it even mean to have a lambda reference to a variable who's stack frame has already popped?
That bit is simple - the variable is kept alive as long as there is still a lambda that references it.
Don’t think about stacks - that’s an implementation detail and the compiler is free to use a combination of the stack and the heap to implement local variables.
The issue I’m talking about is if one thread writes a local and another reads it, what does that look like?