From df8c86766b4a0582e800c2d84fff1edc266d2f2e Mon Sep 17 00:00:00 2001 From: Ian Griffiths Date: Wed, 19 Jul 2023 19:00:18 +0100 Subject: [PATCH 1/3] Define capture behavior when primary ctor bypassed --- proposals/primary-constructors.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/proposals/primary-constructors.md b/proposals/primary-constructors.md index d763f899a2..92d04548a5 100644 --- a/proposals/primary-constructors.md +++ b/proposals/primary-constructors.md @@ -160,6 +160,8 @@ If a primary constructor parameter is referenced from within an instance member, Capturing is not allowed for parameters that have ref-like type, and capturing is not allowed for `ref`, `in` or `out` parameters. This is similar to a limitation for capturing in lambdas. +Structs present a challenge for primary constructor parameter capture: there is no way to enforce the execution of constructors on structs. (For example, creating a single-element array of some struct type will produce an instance of that type without running any of its constructors.) Section [§9.2.5](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/variables#925-value-parameters) of the C# spec states that constructor parameters do not come into existence until the constructor is invoked. Since primary constructor parameters are in scope throughout the type, this can create the awkward situation in which a parameter is in scope, but does not actually exist. If a parameter of a struct's primary constructor is captured, this would mean that the member causing its capture would be using a variable that does not exist. To avoid this, we assert that in cases where an instance of a type with a primary constructor was created through a mechanism that bypasses that constructor, all captured parameters come into existence when the instance is created, and are all initialized with the default value for their type. + If a primary constructor parameter is only referenced from within instance member initializers, those can directly reference the parameter of the generated constructor, as they are executed as part of it. Primary Constructor will do the following sequence of operations: From 1f66023623e46b8542b6326f69137efb2d4b7daf Mon Sep 17 00:00:00 2001 From: Ian Griffiths Date: Thu, 20 Jul 2023 07:30:15 +0100 Subject: [PATCH 2/3] Make wording less negative --- proposals/primary-constructors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/primary-constructors.md b/proposals/primary-constructors.md index 92d04548a5..d1d0db5294 100644 --- a/proposals/primary-constructors.md +++ b/proposals/primary-constructors.md @@ -160,7 +160,7 @@ If a primary constructor parameter is referenced from within an instance member, Capturing is not allowed for parameters that have ref-like type, and capturing is not allowed for `ref`, `in` or `out` parameters. This is similar to a limitation for capturing in lambdas. -Structs present a challenge for primary constructor parameter capture: there is no way to enforce the execution of constructors on structs. (For example, creating a single-element array of some struct type will produce an instance of that type without running any of its constructors.) Section [§9.2.5](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/variables#925-value-parameters) of the C# spec states that constructor parameters do not come into existence until the constructor is invoked. Since primary constructor parameters are in scope throughout the type, this can create the awkward situation in which a parameter is in scope, but does not actually exist. If a parameter of a struct's primary constructor is captured, this would mean that the member causing its capture would be using a variable that does not exist. To avoid this, we assert that in cases where an instance of a type with a primary constructor was created through a mechanism that bypasses that constructor, all captured parameters come into existence when the instance is created, and are all initialized with the default value for their type. +There are circumstances in which constructors do not run. (For example, creating a single-element array of some struct type will produce an instance of that type without running any of its constructors.) Section [§9.2.5](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/variables#925-value-parameters) of the C# spec states that constructor parameters do not come into existence until the constructor is invoked. If a primary constructor parameter is captured in such a scenario, this would mean that the member causing its capture would be using a variable that does not exist. To avoid this, we assert that in cases where an instance of a type with a primary constructor was created through a mechanism that bypasses that constructor, all captured parameters come into existence when the instance is created, and are all initialized with the default value for their type. If a primary constructor parameter is only referenced from within instance member initializers, those can directly reference the parameter of the generated constructor, as they are executed as part of it. From 4087b748041ba8fea5ab8833ff5844a67cab9a60 Mon Sep 17 00:00:00 2001 From: Ian Griffiths Date: Fri, 21 Jul 2023 07:54:26 +0100 Subject: [PATCH 3/3] Use simpler no-constructor initialization example --- proposals/primary-constructors.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/proposals/primary-constructors.md b/proposals/primary-constructors.md index d1d0db5294..175f732791 100644 --- a/proposals/primary-constructors.md +++ b/proposals/primary-constructors.md @@ -160,7 +160,7 @@ If a primary constructor parameter is referenced from within an instance member, Capturing is not allowed for parameters that have ref-like type, and capturing is not allowed for `ref`, `in` or `out` parameters. This is similar to a limitation for capturing in lambdas. -There are circumstances in which constructors do not run. (For example, creating a single-element array of some struct type will produce an instance of that type without running any of its constructors.) Section [§9.2.5](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/variables#925-value-parameters) of the C# spec states that constructor parameters do not come into existence until the constructor is invoked. If a primary constructor parameter is captured in such a scenario, this would mean that the member causing its capture would be using a variable that does not exist. To avoid this, we assert that in cases where an instance of a type with a primary constructor was created through a mechanism that bypasses that constructor, all captured parameters come into existence when the instance is created, and are all initialized with the default value for their type. +There are circumstances in which constructors do not run. (For example, `default(StructType)` will produce an instance of `StructType` without running any of its constructors.) Section [§9.2.5](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/language-specification/variables#925-value-parameters) of the C# spec states that constructor parameters do not come into existence until the constructor is invoked. If a primary constructor parameter is captured in such a scenario, this would mean that the member causing its capture would be using a variable that does not exist. To avoid this, we assert that in cases where an instance of a type with a primary constructor was created through a mechanism that bypasses that constructor, all captured parameters come into existence when the instance is created, and are all initialized with the default value for their type. If a primary constructor parameter is only referenced from within instance member initializers, those can directly reference the parameter of the generated constructor, as they are executed as part of it.