Options for lambdas

Jens Gustedt (INRIA France)

org: ISO/IEC JCT1/SC22/WG14 document: N2893
target: IS 9899:2023 version: 1
date: 2021-12-25 license: CC BY

Revision history

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

Introduction

N2892 now introduces two main forms of captures for lambdas

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 =.

Proposed optional features

Default captures

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 &.

Design

Already the C++ feature only allows for three types of capture lists.

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.

Shadow captures

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:

Syntax ambiguity

The new grammar as proposed has two new lexical ambiguities.

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.

Proposed wording

Default captures

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-capture

default-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 and id 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 capture id 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 form id = 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.

Shadow captures

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.

Syntax ambiguity

Modify 5.1.1.2 (Translation phases) p1 item 7.

  1. 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).