https://issues.dlang.org/show_bug.cgi?id=23136
--- Comment #2 from Bolpat <qs.il.paperinik@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 , )
```
--
|