Skip to content

[Version 11.0] Feature support for ref fields and scoped#1614

Draft
RexJaeschke wants to merge 15 commits intodraft-v11from
v11-ref-fields-and-scoped
Draft

[Version 11.0] Feature support for ref fields and scoped#1614
RexJaeschke wants to merge 15 commits intodraft-v11from
v11-ref-fields-and-scoped

Conversation

@RexJaeschke
Copy link
Copy Markdown
Contributor

@RexJaeschke RexJaeschke commented Mar 28, 2026

Under Construction

This is Rex's adaptation of the corresponding MS proposal.

Open Issues

  1. This Draft PR section 9.7.3, “The scoped modifier”
    Numerous places in the spec now point back to this section. It is very likely more needs to be said here.
  2. Implicitly scoped parameters
    The MS proposal has a section called “Implicitly scoped parameters.” From that, I have added text to say that an output parameter is implicitly scoped, but made no other changes regarding that section. Are other changes needed?
  3. Infer safe-context of declaration expressions
    The MS proposal has a section called “Infer safe-context of declaration expressions.” I made no changes for that section. Are changes needed?
  4. Deconstruction expressions
    The MS proposal has a section called “Deconstruction expressions” whose contents are “[TBD].” What, if anything do we need to say about this proposal in that context?
  5. Return-only safe context
    The MS proposal has a section called “Return-only safe context.” I made no changes for that section; however, presumably, changes are needed.
  6. Rules for method invocation
    The MS proposal has a section called “Rules for method invocation.” I made no changes for that section; however, presumably, changes are needed.
  7. Rules for object initializers
    The MS proposal has a section called “Rules for object initializers.” I made no changes for that section; however, presumably, changes are needed.
  8. Method arguments must match
    The MS proposal has a section called “Method arguments must match.” I made no changes for that section; however, presumably, changes are needed.
  9. Parameter scope variance
    The MS proposal has a section called “Parameter scope variance.” I made no changes for that section; however, presumably, changes are needed.
  10. Initializers with ref values in new and with expressions
    The MS proposal has a section called “Initializers with ref values in new and with expressions.” I made the grammar changes only. Perhaps other changes are needed based on the accompanying narrative.
  11. Changes in unsafe context
    The MS proposal has a section called “Changes in unsafe context.” I made no changes for that section, but surely some are needed.
  12. ScopedRefAttribute
    The MS proposal has a section called “ScopedRefAttribute.” I made no changes for that section, as that appears to be an implementation detail.
  13. RefSafetyRulesAttribute
    The MS proposal has a section called “RefSafetyRulesAttribute.” I made no changes for that section, as that appears to be an implementation detail.
  14. Change the design to avoid compat breaks
    The MS proposal has a section called “Change the design to avoid compat breaks.” I made no changes for that section, but some are probably needed.
  15. Related Information
    The MS proposal has a 14-page section (with numerous subsections) called “Related Information.” I made no changes for that section; it all looks like background reading, but perhaps one or more examples from here might be useful in the spec.

@RexJaeschke RexJaeschke added this to the C# 11 milestone Mar 28, 2026
@RexJaeschke RexJaeschke added type: feature This issue describes a new feature Review: pending Proposal is available for review labels Mar 28, 2026
Copy link
Copy Markdown
Member

@BillWagner BillWagner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Keeping notes on my first read. Some concerns and questions to answer as I read through everything again.


### §UnscopedRefAttribute The UnscopedRef attribute

There are several cases in which a ref is treated as being implicitly scoped; that is, the ref is not allowed to escape a method. For example:
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd consider putting the xref on this paragraph. The section on the scoped modifier defines what it means.

>
> *end example.*

A reference variable can be scoped explicitly; see §scoped-modifier.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This needs more qualification. It's true for local variables and parameters, but not for reference fields in a ref struct.

- For a ref reassignment `e1 = ref e2`, the ref-safe-context of `e2` shall be at least as wide a context as the *ref-safe-context* of `e1`.
- For a ref return statement `return ref e1`, the ref-safe-context of `e1` shall be the caller-context.

### §scoped-modifier The scoped modifier
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see any restriction here or in the grammar that the scoped modifier can only be applied to local variables and parameters.


> *Note*: Initialization to default values is typically done by having the memory manager or garbage collector initialize memory to all-bits-zero before it is allocated for use. For this reason, it is convenient to use all-bits-zero to represent the null reference. *end note*

To test if a ref variable has been assigned a referent, call `System.Runtime.CompilerServices.Unsafe.IsNullRef(ref fieldName)`.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this paragraph be informative rather than normative? Possibly combined with the note that follows.


### §scoped-modifier The scoped modifier

The contextual keyword `scoped` is used as a modifier to restrict the ref-safe-context ([§9.7.2](variables.md#972-ref-safe-contexts)) or safe-context ([§16.5.15](structs.md#16515-safe-context-constraint)) of a variable. The presence of this modifier asserts that related code doesn’t extend the lifetime of the variable.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think "asserts" is the right verb here. Maybe state it this way:

Suggested change
The contextual keyword `scoped` is used as a modifier to restrict the ref-safe-context ([§9.7.2](variables.md#972-ref-safe-contexts)) or safe-context ([§16.5.15](structs.md#16515-safe-context-constraint)) of a variable. The presence of this modifier asserts that related code doesn’t extend the lifetime of the variable.
The contextual keyword `scoped` is used as a modifier to restrict the ref-safe-context ([§9.7.2](variables.md#972-ref-safe-contexts)) or safe-context ([§16.5.15](structs.md#16515-safe-context-constraint)) of a variable. The presence of this modifier requires that related code doesn’t extend the lifetime of the variable.

- one of the following value types: `sbyte`, `byte`, `short`, `ushort`, `int`, `uint`, `nint`, `nuint`, `long`, `ulong`, `char`, `float`, `double`, `decimal`, `bool`; or
- any enumeration type.

A reference variable field `rv` of type `T`, may not have an explicit initializer of `default`.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two thinks to checK:

  1. Can a ref variable be ref initialized to point to something (e.g. ref int iRef = ref parameter;) and to the default reference (e.g. ref int iRef = ref default;).

> var orders = new Dictionary<int,Order>();
> ref var j = ref i;
> ref readonly var k = ref i;
> scoped var r = new RS(); // ref struct RS {}
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In all cases, I think a more realistic example for the Ref Struct type would be one that takes a single parameter that's a ref. That illustrates the reason for scoped restrictions:

scoped var r = new RS(ref orders);

Or similar. This should apply to all examles using RS

@@ -569,7 +569,7 @@ argument_value
: expression
| 'in' variable_reference
| 'ref' variable_reference
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Need to verify, but I think scoped can be applied to both in and ref variables:

Suggested change
| 'ref' variable_reference
| 'in' 'scoped'? variable_reference
| 'ref' 'scoped'? variable_reference


It is a compile time error if the ref-safe-context ([§9.7.2](variables.md#972-ref-safe-contexts)) of the left operand is wider than the ref-safe-context of the right operand.

The left operand shall have the same safe-context as the right operand.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a stronger restriction than the one on L7172. L7172 can be deleted, with the appropriate link to 9.7.2 added here.

- The keyword `in` followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as an input parameter ([§15.6.2.3.2](classes.md#156232-input-parameters)). A variable shall be definitely assigned ([§9.4](variables.md#94-definite-assignment)) before it can be passed as an input parameter.
- The keyword `ref` followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as a reference parameter ([§15.6.2.3.3](classes.md#156233-reference-parameters)). A variable shall be definitely assigned ([§9.4](variables.md#94-definite-assignment)) before it can be passed as a reference parameter.
- The keyword `out` followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as an output parameter ([§15.6.2.3.4](classes.md#156234-output-parameters)). A variable is considered definitely assigned ([§9.4](variables.md#94-definite-assignment)) following a function member invocation in which the variable is passed as an output parameter.
- The keyword `out` optionally followed by `scoped`, optionally followed by a *variable_reference* ([§9.5](variables.md#95-variable-references)), indicating that the argument is passed as an output parameter ([§15.6.2.3.4](classes.md#156234-output-parameters)). A variable is considered definitely assigned ([§9.4](variables.md#94-definite-assignment)) following a function member invocation in which the variable is passed as an output parameter. For a discussion of `scoped`, see §scoped-modifier.
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per above, I think these changes need to be applied to L581 and L582 for ref and in variables.

@BillWagner
Copy link
Copy Markdown
Member

Notes on the open issues:

  1. This Draft PR section 9.7.3, “The scoped modifier”
    Numerous places in the spec now point back to this section. It is very likely more needs to be said here.
    This section could use a few examples (possibly from the notes in item 15). The examples should demonstrate how the scoped modifier prevents constructs that could cause ref variables to become invalide.
  2. Implicitly scoped parameters
    The MS proposal has a section called “Implicitly scoped parameters.” From that, I have added text to say that an output parameter is implicitly scoped, but made no other changes regarding that section. Are other changes needed?
    The this parameter of a struct is also implicitly scoped.
  3. Infer safe-context of declaration expressions
    The MS proposal has a section called “Infer safe-context of declaration expressions.” I made no changes for that section. Are changes needed?
    Yes, the safe context sections (9.7.2 and 16.4.15) will need updates
  4. Deconstruction expressions
    The MS proposal has a section called “Deconstruction expressions” whose contents are “[TBD].” What, if anything do we need to say about this proposal in that context?
    I don't think so. I don't think that was implemented.
  5. Return-only safe context
    The MS proposal has a section called “Return-only safe context.” I made no changes for that section; however, presumably, changes are needed.
    Yes, again, 9.7.2 and 16.4.15 need updates.
  6. Rules for method invocation
    The MS proposal has a section called “Rules for method invocation.” I made no changes for that section; however, presumably, changes are needed.
    Yes, these are also changes in 9.7.2 and 16.4.15.
  7. Rules for object initializers
    The MS proposal has a section called “Rules for object initializers.” I made no changes for that section; however, presumably, changes are needed.
    Yes, these rules require changes to 9.7.2 and 16.4.15.
  8. Method arguments must match
    The MS proposal has a section called “Method arguments must match.” I made no changes for that section; however, presumably, changes are needed.
    yes, again, 9.7.2 and 16.4.15.
  9. Parameter scope variance
    The MS proposal has a section called “Parameter scope variance.” I made no changes for that section; however, presumably, changes are needed.
    Yes, again 9.7.2 and 16.4.15.
  10. Initializers with ref values in new and with expressions
    The MS proposal has a section called “Initializers with ref values in new and with expressions.” I made the grammar changes only. Perhaps other changes are needed based on the accompanying narrative.
    Yes, these initializers must obey the rules in 9.7.2 and 16.4.15, which might also change to support this.
  11. Changes in unsafe context
    The MS proposal has a section called “Changes in unsafe context.” I made no changes for that section, but surely some are needed.
    This is mostly a change by subtraction: The rules that restrict the types that can be referred to by pointers. The restrictions around unmanaged types should be removed.
  12. ScopedRefAttribute
    The MS proposal has a section called “ScopedRefAttribute.” I made no changes for that section, as that appears to be an implementation detail.
    This is an implementation detail. We might make a note in the Attributes clause to reserve this name for this purpose is the only change needed.
  13. RefSafetyRulesAttribute
    The MS proposal has a section called “RefSafetyRulesAttribute.” I made no changes for that section, as that appears to be an implementation detail.
    This is an implementation detail. It should not be part of the standard.
  14. Change the design to avoid compat breaks
    The MS proposal has a section called “Change the design to avoid compat breaks.” I made no changes for that section, but some are probably needed.
    No changes are needed. The design was approved with the breaks.
  15. Related Information
    The MS proposal has a 14-page section (with numerous subsections) called “Related Information.” I made no changes for that section; it all looks like background reading, but perhaps one or more examples from here might be useful in the spec.
    Yes, many of these would be great informative (Example:) additions to illustrate the reasons for any of the rules.

@RexJaeschke RexJaeschke marked this pull request as draft April 3, 2026 19:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Review: pending Proposal is available for review type: feature This issue describes a new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants