Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Field-backed properties: language version diagnostics #9038

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

cston
Copy link
Member

@cston cston commented Jan 9, 2025

Document the breaking change diagnostics that may be reported when re-compiling with the language version that includes field-backed properties.

@cston cston requested a review from a team as a code owner January 9, 2025 22:43

If a variable named `field` is declared in a property accessor, an error is reported.

If an expression `field` would bind to a symbol with language version 13 or earlier, a warning may be reported.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Why "may" here? Can we make it "will" and better describe the situation if necessary.

Would it be more clear to say something like

Suggested change
If an expression `field` would bind to a symbol with language version 13 or earlier, a warning may be reported.
If a symbol named `field` is accessible in the body of a setter or getter that uses the `field` keyword, a warning will be reported. "Accessible" here means that a symbol is available that would be used for binding, if it did not conflict with the `field` keyword.

Copy link
Member Author

@cston cston Jan 10, 2025

Choose a reason for hiding this comment

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

Thanks. Changed to "is" rather than "may be".

In terms of accessibility, we should state that it's accessible at the reference to field. For instance, the following is valid, even though the field local is accessible at other locations in the accessor body.

object Property
{
    get
    {
        if (field == null)
        {
            int @field = 0;
            return @field;
        }
        return field;
    }
}

@cston cston requested review from CyrusNajmabadi and jnm2 January 10, 2025 21:55

If a variable named `field` is declared in a property accessor, an error is reported.

If an expression `field` would bind to an existing symbol with language version 13 or earlier, a warning is reported.
Copy link
Member

Choose a reason for hiding this comment

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

Can we clarify that this must be a primary expression? Essentially, field will warn but this.field willl not.

Copy link
Contributor

@jnm2 jnm2 left a comment

Choose a reason for hiding this comment

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

My hesitation with "warnings after upgrade" instead of "warnings before upgrade" is the small chance of this scenario:

  • There's something called field in scope. Let's say a protected field in a base class you're implementing from a library that you can't edit.

  • You write a new property using field as a keyword. This code is good code.

  • The brand-new, correct code gets hit with a warning that field would have bound to the inherited field named field in C# 13, despite this new property never having compiled with C# 13.

There are variations on this scenario as well. Switching to langversion 14, and bulk applying "use field," could land you with this same warning despite the new occurrences of field being correct, and never having existed under C# 13.

So what does a user do?

  • Rename the class field, but this might be a bitter pill if field was a genuinely good name for the class field. This might be impossible too, if inheriting from a third-party class.

  • Or, put a #pragma warning disable on each prop. That's a lot of noise especially for a view model class.

  • Or, put a #pragma warning disable once at the top of the file because of how noisy the warning is: it's basically all false positives. This is weird, because now in the one place where confusion is likely (where there's a class field called field), the user has disabled the warning.

    • Or, disable the warning project-wide.
  • Or, quit using the field keyword feature in scope of the class field.

In short: Anytime this warning matters (in scenarios where there's something in scope called field), I expect the occurrences of our breaking changes warning to be absolutely dominated by false positives, and for it to be tuned out one way or another. At the same time I agree we need something.

Regardless of the above, making it an error to declare something called field inside a property accessor seems like a solid move.

Does this apply to lambda parameters and local function parameters named field, or only locals?

@jaredpar
Copy link
Member

The cases that would require a permanent warning are essentially when you both:

  1. Have an accessible API named field which the developer cannot or will not rename
  2. Have a property where you desire the new behavior of the field keyword

Our belief is the intersection of these two items will be low. It also falls in line with our stance that this is a breaking change and potentially requires changes to adopt. Yes there are a few cases that can be outlined where you cannot rename the member but those feel sufficiently small. The vast majority of use cases we've seen don't have this intersection of problems.

Warnings on upgrade is a problematic area that carry a lot of risk for the product. In this case we feel like the scenarios where customers would be required to use a permanent #pragma warning disable are small enough that we'd rather take the certainty around warn on upgrade vs. the risk of warn on upgrade.

@cston
Copy link
Member Author

cston commented Jan 13, 2025

Regardless of the above, making it an error to declare something called field inside a property accessor seems like a solid move.

Does this apply to lambda parameters and local function parameters named field, or only locals?

The error applies to parameters named field from lambdas, anonymous functions, and local functions nested in the accessor, in addition to locals declared in the accessor or in nested functions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants