Explicit captures in lambda expression
Attila Kelemen
attila.kelemen85 at gmail.com
Tue Jan 7 15:53:23 UTC 2025
I didn't mean for the lambda to unassign the variable, I was just lazy to
write it out exactly: I meant that the variable is DU after lambda if we
assume that the variable is DU at the point of capturing (basically we
pretend that the variable is DU even though it is actually DA). Consider
this code (doesn't compile, but I think it should).
int x = 5;
if (test) x = 6;
new Thread(() -> { System.out.println("Hello: " + x) }).start();
I don't really see why this shouldn't compile.
Robbe Pincket <robbepincket at live.be> ezt írta (időpont: 2025. jan. 7., K,
14:58):
> > the lambda capture rule should be is that the variable can be captured
> if it is definitely assigned before the lambda, and definitely not assigned
> after the lambda.
>
> I'm very confused by what you mean. A lambda can't "unassign" a variable.
> So I don't see in what cases a variable can be DA before the labmda and
> definietely unassigned afterwards (ignoring unreachable code in `if(false)`
> blocks)
>
> Greetings
> Robbe Pincket
>
> ------------------------------
> *Van:* amber-dev <amber-dev-retn at openjdk.org> namens Attila Kelemen <
> attila.kelemen85 at gmail.com>
> *Verzonden:* dinsdag 7 januari 2025 13:31
> *Aan:* Quân Anh Mai <anhmdq at gmail.com>
> *CC:* amber-dev at openjdk.org <amber-dev at openjdk.org>
> *Onderwerp:* Re: Explicit captures in lambda expression
>
> I like this idea, because I run into bugs of accidentally capturing "this"
> so many times, and the least of the problems when this causes a crash (like
> serialization issues), but sometimes it "just" creates a potentially huge
> unwanted memory retention. The workaround of moving the lambda declaration
> into a separate static method is very-very tedious.
>
> I do not however care so much about non-final capture (I'm not sure if it
> should even be allowed). What - in my opinion - the lambda capture rule
> should be is that the variable can be captured if it is definitely assigned
> before the lambda, and definitely not assigned after the lambda.
>
> Also, I don't think `[t = x]` is needed, I think that part just
> complicates the language with very little gain. Just allowing an explicit
> variable name capture list should be enough.
>
> Attila
>
> Quân Anh Mai <anhmdq at gmail.com> ezt írta (időpont: 2025. jan. 7., K,
> 7:17):
>
> To add more context regarding JDK-8347047, even without the core lib bug,
> the method is easily misused. The method in consideration looks like this:
>
> MemorySegment MemorySegment::reinterpret(long size,
> Consumer<MemorySegment> cleanup)
>
> `cleanup` is triggered when the returned segment is closed, which for some
> kind of MemorySegment, is at the time the old MemorySegment instance (this)
> and the new MemorySegment instance (the returned segment) are
> garbage-collected. As a result, `cleanup` must not reference the old
> segment instance. It is given a freshly created MemorySegment instance and
> must use it. However, it is easy to mistakenly use the old instance instead:
>
> MemorySegment oldMs;
> oldMs.reinterpret(size, ms -> free(oldMs));
>
> While it should be:
>
> oldMs.reinterpret(size, ms -> free(ms));
>
> With explicit captures, it is easy to see if oldMs is mistakenly captured
> as this would not compiled:
>
> oldMs.reinterpret(size, [](ms) -> free(oldMs));
>
> Cheers,
> Quan Anh
>
> On Tue, 7 Jan 2025 at 12:30, Quân Anh Mai <anhmdq at gmail.com> wrote:
>
> Hi,
>
> A feature I missed from C++ is explicit captures in lambda expressions and
> from recent events I think that it may be a valuable feature to have in
> Java.
>
> JEP-8341785[1] proposes treating loop variables as final inside the loop
> body, the main motivation is to allow their usage in lambda expressions
> inside the loop body. However, it seems to be withdrawn due to the concern
> of making an exception. I believe explicit captures would remove the
> condition that the variable being captured needs to be effectively final,
> resolving the motivation of JEP-8341785 and many other cases.
>
> JDK-8347047[2] is a bug caused by the implicit capture of the this
> reference inside a lambda, which leads to the object never being reclaimed
> by the garbage collector, the thing we actually want to capture there is
> the result of the method call this.address(). In this case, implicit
> captures is very error-prone and it would be better if we can explicitly
> declare what we want to capture instead to avoid accidentally capturing
> unwanted variables.
>
> As a result, I propose that:
>
> - A lambda expression can optionally have a captures, if that is the case,
> all the variables being captured by the lambda expression need to be
> declared inside it.
> - We can capture an effectively final variable without giving it another
> name, but for the others, to avoid confusion, another name for the variable
> is needed.
>
> E.g, suppose a, b are effectively final variables and x, y are not:
>
> () -> a; // Allowed, implicit capture of a
> []() -> a; // Disallowed, a is not captured and hence not defined here
> [a]() -> a; // Allowed, explicit capture of a
> [a, b]() -> a + b; // Allowed, capture 2 variables
> () -> x; // Disallowed, cannot implicitly capture non-effectively-final
> variable
> [x]() -> x; // Disallowed, capture a non-effectively-final without
> reassignment
> [t = x]() -> x; // Disallowed, x is not defined here
> [t = x]() -> t; // Allowed, x is captured and assigned to the variable t
> inside the lambda
> [t = this.address()]() -> t; // Maybe?
>
> Cheers,
> Quan Anh
>
> [1]: https://openjdk.org/jeps/8341785
> [2]: https://bugs.openjdk.org/projects/JDK/issues/JDK-8347047
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-dev/attachments/20250107/5ba7fa06/attachment.htm>
More information about the amber-dev
mailing list