diff --git a/3273_introspect-closure/introspect-closure.md b/3273_introspect-closure/introspect-closure.md index d57c5535..cfa5b14a 100644 --- a/3273_introspect-closure/introspect-closure.md +++ b/3273_introspect-closure/introspect-closure.md @@ -21,21 +21,21 @@ toc: true # Introduction -Recent proposals of reflection facilities for C++ (such as [@P2996R2] and [@P3157R0]) raise important questions regarding the applicability of reflection to the layout of closure types. The ability to introspect closure types has important applications to applications that need to carry computation and data—packaged together in closures—across address spaces: inter-process communication, networking, serialization, and GPU execution. We propose to strenghten the layout guarantees of closure types in ways that allow introspection to work appropriately. To the best of our knowledge, the guarantees we propose are already observed by current implementations, so we estimate no or low impact on existing compiler infrastructure. +Recent proposals of reflection facilities for C++ (such as [@P2996R2] and [@P3157R0]) raise important questions regarding the applicability of reflection to the layout of closure types (the types of lambda expressions). The ability to introspect closure types has important applications to programs that need to carry computation and data—packaged together in closures—across address spaces: inter-process communication, networking, serialization, and GPU execution. We propose to strenghten the layout guarantees of closure types in ways that allow introspection to work appropriately. To the best of our knowledge, the guarantees we propose are already observed in current implementations, so we estimate no or low impact on existing compiler infrastructure. # Motivation -Closure objects are a simple, syntactically compact, and convenient means to package computation and data together. Captures allow closures to carry arbitrary amounts of data within. Because of these advantages, closures are used extensively in C++ code either as a means to customize algorithms, or in various applications of the [Command](https://en.wikipedia.org/wiki/Command_pattern) design pattern. +Closure objects are a simple, syntactically compact, and convenient means to package computation and data together. Captures allow closures to carry arbitrary amounts of data within. Because of these advantages, closures are used extensively in C++ code, either as a means to customize algorithms, or in various applications of the [Command](https://en.wikipedia.org/wiki/Command_pattern) design pattern. -The CUDA C++ dialect aimed at running algorithms on GPU devices with dedicated computational and memory hardware pays special attention to closure types, making them transparently available for execution on GPU hardware. Libraries such as [Thrust](https://developer.nvidia.com/thrust) and [Cub](https://docs.nvidia.com/cuda/cub/index.html) make good use of device lambda functions as a central feature. +The CUDA C++ dialect aimed at running algorithms on GPU devices with dedicated computational and memory hardware pays special attention to closure types, making them transparently available for execution on GPU hardware, dispatching to the right generated code, depending on where the lambda is invoked from. Libraries such as [Thrust](https://developer.nvidia.com/thrust), a GPU implementation of the parallel STL, and [Cub](https://docs.nvidia.com/cuda/cub/index.html), reusable algorithmic components for CUDA, make good use of such CPU- and GPU-side-executable lambda functions as a central feature. This special handling of closure types is not specific to CUDA C++ only. -Introspection of closure types promises new opportunities for such codes as well as any code that needs to marshal data and computation across memory address spaces. To realize such opportunities, closure types must make their state available for introspection so that custom code can carry marshaling operations, or disallow certain data statically or dynamically. +Introspection of closure types promises new opportunities for any such codes that need to marshal data and computation across memory address and execution spaces. To realize such opportunities, closure types must make their state available for introspection (e.g., by type traits and reflection) so that custom code can carry out marshaling operations, or disallow certain data statically or dynamically. An important trait, for example, is whether a closure type is trivially copyable. # Proposed Changes: Specify Storage of Reference Captures -Given that the introspection primitives proposed in P2996 can query class types and that closure types are class types (per [expr.prim.lambda.closure]{.sref}), it follows that introspection should apply by definition to closure types. However, there is one specific issue with reference captures: per [expr.prim.lambda.capture]{.sref}, the language definition leaves it to the implementation whether member variables are declared in the closure type to accommodate those captures. This makes it impossible for code that uses introspection for closure objects to portably take account of all captured data. +Given that the introspection primitives proposed in P2996 can query class types and that closure types are class types (per [expr.prim.lambda.closure]{.sref}), it follows that introspection should apply to closure types by definition. However, there is one specific issue with reference captures: per [expr.prim.lambda.capture]{.sref}, the language definition leaves it to the implementation whether member variables are declared in the closure type to accommodate those captures, and how those captures are represented. This makes it impossible for code that uses introspection for closure objects to portably take account of all captured data. -We propose to change wording in [expr.prim.lambda.capture]{.sref}/12: +We propose to change the wording in [expr.prim.lambda.capture]{.sref}/12 to specify the behavior for reference captures: ::: std [12]{.pnum} An entity is *captured by reference* if it is implicitly or explicitly captured but not captured by copy. [It is unspecified whether additional unnamed non-static data members are declared in the closure type for entities captured by reference. If declared, such non-static data members shall be of literal type.]{.rm} [For each entity captured by reference, an unnamed non-static data member is declared in the closure type. The declaration order of these members is unspecified. The type of such a data member is an lvalue reference to:]{.addu} @@ -49,5 +49,5 @@ We propose to change wording in [expr.prim.lambda.capture]{.sref}/12: As mentioned, to our knowledge, all implementations already implement by-reference lambda captures by means of reference or pointer members, so we anticipate no or small impact on compiler implementations. -To the extent the intent of the existing wording was meant to allow optimizations (e.g., use direct access for reference captures when the lambda is executed directly upon introduction), we note that all optimizations are still possible if reflection facilities are not used for any given lambda. +To the extent the intent of the existing wording was meant to allow optimizations (e.g., directly accessing variables captured by reference when the lambda is executed immediately upon definition), we note that all optimizations are still possible if reflection facilities are not used to observe the structure of a closure type. diff --git a/3273_introspect-closure/p3273r0.html b/3273_introspect-closure/p3273r0.html index 70516630..51929dc4 100644 --- a/3273_introspect-closure/p3273r0.html +++ b/3273_introspect-closure/p3273r0.html @@ -4,7 +4,7 @@ - +
Recent proposals of reflection facilities for C++ (such as [P2996R2] and [P3157R0]) raise important questions -regarding the applicability of reflection to the layout of closure -types. The ability to introspect closure types has important -applications to applications that need to carry computation and -data—packaged together in closures—across address spaces: inter-process -communication, networking, serialization, and GPU execution. We propose -to strenghten the layout guarantees of closure types in ways that allow -introspection to work appropriately. To the best of our knowledge, the -guarantees we propose are already observed by current implementations, -so we estimate no or low impact on existing compiler infrastructure.
+regarding the applicability of reflection to the layout of closure types +(the types of lambda expressions). The ability to introspect closure +types has important applications to programs that need to carry +computation and data—packaged together in closures—across address +spaces: inter-process communication, networking, serialization, and GPU +execution. We propose to strenghten the layout guarantees of closure +types in ways that allow introspection to work appropriately. To the +best of our knowledge, the guarantees we propose are already observed in +current implementations, so we estimate no or low impact on existing +compiler infrastructure.Closure objects are a simple, syntactically compact, and convenient means to package computation and data together. Captures allow closures to carry arbitrary amounts of data within. Because of these advantages, -closures are used extensively in C++ code either as a means to customize -algorithms, or in various applications of the Command design +closures are used extensively in C++ code, either as a means to +customize algorithms, or in various applications of the Command design pattern.
The CUDA C++ dialect aimed at running algorithms on GPU devices with dedicated computational and memory hardware pays special attention to closure types, making them transparently available for execution on GPU -hardware. Libraries such as Thrust and Cub make good use -of device lambda functions as a central feature.
-Introspection of closure types promises new opportunities for such -codes as well as any code that needs to marshal data and computation -across memory address spaces. To realize such opportunities, closure -types must make their state available for introspection so that custom -code can carry marshaling operations, or disallow certain data -statically or dynamically.
+hardware, dispatching to the right generated code, depending on where +the lambda is invoked from. Libraries such as Thrust, a GPU +implementation of the parallel STL, and Cub, reusable +algorithmic components for CUDA, make good use of such CPU- and +GPU-side-executable lambda functions as a central feature. This special +handling of closure types is not specific to CUDA C++ only. +Introspection of closure types promises new opportunities for any +such codes that need to marshal data and computation across memory +address and execution spaces. To realize such opportunities, closure +types must make their state available for introspection (e.g., by type +traits and reflection) so that custom code can carry out marshaling +operations, or disallow certain data statically or dynamically. An +important trait, for example, is whether a closure type is trivially +copyable.
Given that the introspection primitives proposed in P2996 can query class types and that closure types are class types (per 7.5.5.2 [expr.prim.lambda.closure]), -it follows that introspection should apply by definition to closure -types. However, there is one specific issue with reference captures: per -7.5.5.3 [expr.prim.lambda.capture], +it follows that introspection should apply to closure types by +definition. However, there is one specific issue with reference +captures: per 7.5.5.3 [expr.prim.lambda.capture], the language definition leaves it to the implementation whether member variables are declared in the closure type to accommodate those -captures. This makes it impossible for code that uses introspection for -closure objects to portably take account of all captured data.
-We propose to change wording in 7.5.5.3 [expr.prim.lambda.capture]/12:
+captures, and how those captures are represented. This makes it +impossible for code that uses introspection for closure objects to +portably take account of all captured data. +We propose to change the wording in 7.5.5.3 [expr.prim.lambda.capture]/12 +to specify the behavior for reference captures:
12 @@ -671,10 +680,10 @@
To the extent the intent of the existing wording was meant to allow -optimizations (e.g., use direct access for reference captures when the -lambda is executed directly upon introduction), we note that all -optimizations are still possible if reflection facilities are not used -for any given lambda.
+optimizations (e.g., directly accessing variables captured by reference +when the lambda is executed immediately upon definition), we note that +all optimizations are still possible if reflection facilities are not +used to observe the structure of a closure type.5 References