[Issue 23136] closure in a loop should hold distinct values for each iteration
d-bugmail at puremagic.com
d-bugmail at puremagic.com
Wed May 10 10:05:08 UTC 2023
https://issues.dlang.org/show_bug.cgi?id=23136
--- Comment #2 from Bolpat <qs.il.paperinik at gmail.com> ---
This could be solved by allowing captures to be explicitly specified in a
capture list, like C++ lambdas do it.
Here’s how it could be done:
A lambda or non-static local function may have a capture list after the
parameter list and before any constraints and contracts. The capture list is
syntactically expressed with square brackets (or, as an alternative, with
`catch` and parentheses). The capture list is optional; providing no capture
list is equivalent to providing `[ref]` (or `catch(ref)`).
The entries of a capture list are comma-separated.
The first entry of a capture list can be a specially handled token sequence,
called "capture default": It can be `ref` or `auto`. (Otherwise it is handled
like other entries.)
Every other entry must be (Grammar below)
1. `this`, or
2. an Identifier, or
3. `ref` followed by `this`,
4. `ref` followed by an Identifier, or
5. `auto` followed by an Identifier, `=`, and a
[ConditionalExpression](https://dlang.org/spec/expression.html#ConditionalExpression),
or
6. `ref` followed by an Identifier `=`, and a ConditionalExpression, or
7. `auto ref` followed by an Identifier `=`, and a ConditionalExpression.
`this` can be specified at most once and Identifiers must be unique.
(Specifying `this` is only valid in a non-static member function.)
An `auto ref` capture is `auto` if the ConditionalExpression evaluates to an
rvalue and it is `ref` if the ConditionalExpression evaluates to an lvalue.
If the ConditionalExpression is a compile-time sequence (introduced by template
`...` in some way), `auto ref` becomes `auto` or `ref` for each sequence
element individually. (The primary use-case for this is parameter forwarding.)
A capture that includes the `ref` token is called a "reference capture" and a
"value capture" otherwise.
A non-`this` capture without `=` is treated as if it were followed by `=` and
the given identifier, and prefixed by `auto` if it is not `ref`. (This rewrite
is assumed in the following.)
The Identifiers/`this` on the left of `=` in the capture list are called
left-hand sides, the ConditionalExpressions in the capture list are called
right-hand sides.
The left-hand sides are only in scope of the lambda, not its parent.
The right-hand sides are resolved in the scope of the lambda’s parent.
For a value capture, the context of the lambda holds a value that is
initialized by the right-hand side when statement is encountered in which the
lambda resides. If the right-hand side is implicit, the type must be copyable;
a non-copyable type can be used if the right-hand side is an rvalue.
For a reference capture, the context of the lambda holds a reference to the
variable. If the lambda is `scope`, variables that hold the lambda must not
outlive the bound references. (There is no such restriction for value
captures.)
This has two important consequences:
1. Lambdas with value captures are dependent on the exact point of creation.
2. Value captures cannot be shared among lambdas.
In contrast to C++, in D, a lambda with captures may outlive the captured
variables (unless, of course, it is marked `scope`). A local variable that is
captured by a non-`scope` lambda must be allocated on the heap only if the
capture is by reference. A reference parameter cannot be captured unless the
lambda is `scope`.
In contrast to C++, in D, a lambda’s call operator is not `const`; value
captures can be written to (unless, of course, their type is `const` or
`immutable` or the lambda is itself marked `const` or `immutable`).
Grammar:
```
CaptureList:
[ ]
[ CaptureDefault ]
[ CaptureDefault , ]
[ CaptureList ]
[ CaptureList , ]
[ CaptureDefault , Captures ]
[ CaptureDefault , Captures , ]
CaptureDefault:
ref
auto
Captures:
Capture
Capture , Captures
Capture
this
ref this
Identifier
ref Identifier
auto Identifier = ConditionalExpression
ref Identifier = ConditionalExpression
auto ref Identifier = ConditionalExpression
```
As a syntactical alternative, instead of using brackets, the `catch` keyword
could be re-used:
```
CaptureList:
catch ( CaptureDefault )
catch ( CaptureDefault , )
catch ( CaptureList )
catch ( CaptureList , )
catch ( CaptureDefault , Captures )
catch ( CaptureDefault , Captures , )
```
--
More information about the Digitalmars-d-bugs
mailing list