org: | ISO/IEC JCT1/SC22/WG14 | document: | N2893 | |||||
target: | IS 9899:2023 | version: | 1 | |||||
date: | 2021-12-25 | license: | CC BY |
Paper number | Title | Changes |
---|---|---|
N2893 | Options for lambdas | combines optional features on top of N2892: |
shadow captures from N2736 | ||
default shadow captures from N2736 | ||
default identifier captures from N2737 | ||
syntax disambiguation for [ [ … from N2736 |
N2892 now introduces two main forms of captures for lambdas
identifier = expression
.&identifier
.Note that for a value capture identifier
becomes a per-call local variable with that name, much as a function parameter. The rules for evaluation are made that they are similar to function parameters, that is within expression a use of identifier
does not refer to the capture, but to a variable of a surrounding scope, if that exists, or is a syntax error, if it doesn’t.
Not covered by N2892 are what we call shadow captures in the following. These just list an identifier identifier
and are a shortcut for the special value capture identifier = identifier
, that is an lvalue conversion of identifier
and a creation of a new object with the same name that holds that value and that shadows the usage of the outer variable for all calls to the lambda.
Also not covered by N2892 are default captures in the form of &
or =
.
There has been some criticism against default captures =
and &
because they would weaken the model of isolation and, for =
, shadow the use of variables from an outer scope in an unusual way. Nevertheless, we think that it would be important to have both features, such that users of existing extension could migrate more easily. Namely users of Objective C’s blocks would be better served with =
, where users of gcc’s nested functions or compound expressions would be better served with &
.
Already the C++ feature only allows for three types of capture lists.
&
token and then only has value or shadow captures that denote exceptions from the default.=
token and then only has identifier captures that denote exceptions from the default.We now propose to clearly separate these three possibilities syntactically, with three different syntax terms mixed-capture-list, default-identifier-capture-list and default-shadow-capture-list. The latter two are comprised into a default-capture-list such that the term is directly introduced through the syntax.
This first option already introduces shadow captures for two of the cases.
On the other hand shadow captures are not strictly needed for the full semantics. They have been seen critical by some for their property (now reflected in the term itself) that they shadow the visibility of a outer variable inside the function body of a lambda. Therefore the first option does not add them to mixed capture lists.
A second option introduces the term with a subset of the tools described above and anchors them additionally into “capture list element”.
Such an addition looks relatively innocent but it has two drawbacks:
The new grammar as proposed has two new lexical ambiguities.
[identifier]
or [identifier = expression]
may be an array element designator idexed by a variable or an assignment expression (6.7.12 p1) or start a capture clause (6.5.2.6 p1).[ [
may be the start of an attribute specifier (6.7.15.1 p1) or the start of several other constructs that allow an expression within an array bound (6.7.8.2 p1 and 6.7.9 p1 or array subscript 6.5.2 p1.The first may be resolved immediately after a token sequence as indicated above has been scanned. It only requires limited lookahead for resolution, although the occurrence of commas may complicate parsing. Therefore we don’t think this ambiguity needs otherwise to be resolved normatively. WG14 could add a rule that gives priority to the designator reading and force lambda expressions that are used in initializers to be surrounded by parenthesis, but this should be proposed in a different paper.
With the introduction of shadow captures, the second ambiguity needs unbounded lookahead and is therefore more challenging for implementors. C++ helps implementors, here, in making the appearance of a cosecutive pair [ [
other than in attributes undefined. This imposes some care for applications, because with that rule they have to surround lambda expressions with parenthesis, for example in declarations of VLA. We propose this approach as a possible option for WG14.
Change in 6.5.2.6 p1, syntax
capture-list:
mixed-capture-list
default-capture-list
mixed-capture-list:
capture-list-element
mixed-capture-list
,
capture-list-element
default-capture-list:
default-shadow-capture-list
default-identifier-capture-list
default-shadow-capture-list:
=
default-shadow-capture-list
,
identifier-capture
default-identifier-capture-list:
&
default-identifier-capture-list
,
value-capturedefault-identifier-capture-list
,
shadow-capture
shadow-capture:
capture
Change in 6.5.2.6 p2, constraints
2 An identifier shall appear at most once; either as a capture or as a parameter name in the parameter list. The identifier of an identifier or shadow capture shall
designatebe the name of an object of automatic storage duration that is defined in a scope that surrounds the lambda expression. For a shadow capture that object shall not have array type.
Add a new paragraph 6.5.2.6 p3’ before p4 to the constraints
3’ If there is an identifier
id
that is not explicitly listed as a capture,id
is defined with automatic storage duration in a surrounding scope andid
would be evaluated in the function body, the capture list shall be a default capture list;id
is an implicit capture. The effect is the same as for a shadow captureid
or identifier capture&id
, respectively; all constraints for these implicit captures apply.
Add a new paragraph 6.5.2.6 p8’ before p9
8’ The identifier of the object of automatic storage duration of the surrounding scope with the same name as a shadow capture shall be visible at the point of evaluation of the lambda expression. If the identifier of the shadow capture is
id
, the effect is as if a value capture of the formid = id
is used and the declared shadow capture shadows the access to the object of the surrounding scope until the end of the function body.
Add a new paragraph 6.5.2.6 p9’ before p10
9’ The lvalue conversions of the objects of surrounding scopes corresponding to implicit shadow captures are indeterminately sequenced at the beginning of the evaluation of the lambda expression and the implicit shadow captures shadow all further usage of these objects until the end of the function body.
Add the syntax element shadow-capture as above and change in 6.5.2.6 p1, syntax
capture-list-element:
value-capture
shadow-capture
identifier-capture
Change 6.5.2.6 p2 and add p8’ as above.
Modify 5.1.1.2 (Translation phases) p1 item 7.
- White-space characters separating tokens are no longer significant. Each preprocessing token is converted into a token. The resulting tokens are syntactically and semantically analyzed and translated as a translation unit
.; two consecutive[
tokens shall be the initial token sequence of an attribute specifier or of a balanced token (6.7.11.1).