Back to Csharplang

C# Language Design Meeting for March 10th, 2025

meetings/2025/LDM-2025-03-10.md

latest5.5 KB
Original Source

C# Language Design Meeting for March 10th, 2025

Agenda

Quote of the Day

  • "We're starting the boring part of the meeting now"

Discussion

Extensions

Champion issue: https://github.com/dotnet/csharplang/issues/8697
Specification: https://github.com/dotnet/csharplang/blob/82157ff229f6c1bd2954a96ec2acb47064a48bad/proposals/extensions.md

We looked at a few questions in extensions today.

Property method calling

The first question we looked at was whether to allow extension property underlying methods to be called directly on an instance. For example:

cs
_ = new object().Prop; // Allowed
_ = C.get_Prop(new object()); // Previously said this is allowed
_ = new object().get_Prop(); // Should this be allowed?

public static class C
{
    extension (object o)
    {
        public int Prop { get => 1; }
    }
}

We're not sure what the use case for this form is. We allow the get_Prop syntax on C itself to serve as a disambiguation syntax, but we don't know why get_Prop should be visible as a method on object itself. We don't do this for regular properties, so we don't have a reason to allow it for extension properties either. Given this, we will disallow it.

Conclusion

get_Prop form is disallowed in extension method form.

Scoping and Shadowing

Next, we looked at a couple of questions around scoping and shadowing. First, should extension parameter names be in scope in static members, even if they'd be an error to reference, and even if they shadow a field? And second, should instance methods be able to shadow the extension parameter in their own parameter lists? As an example:

cs
public static class E
{
    static string s;
    extension(string s)
    {
        public int M(int i)
        {
            return s.Length + i;
        }
        public static string P => s; // Does this error that the extension parameter s can't be used, or bind to E.s?
        public void M2(string s) { ... } // Should we allow this to shadow the extension parameter?
        public static void M3(string s) { ... } // Should we allow this to shadow the extension parameter, since there's no implicit s?
        public static void M4() { s.ToString(); } // Does this bind to the extension receiver parameter and error, or to E.s?
    }
}

There are a couple of sets of rules we can look to for inspiration here: existing parameter rules, and primary constructor rules. After some thought, we think existing parameter rules are the right inspiration; as mentioned in the previous topic, we keep leaning further towards the extension block being just another parameter. This means it should follow the same rules for other parameters, and when we consider instance extension methods, M2 isn't shadowing anything, it's literally declaring 2 parameters with the same name, which is just not permitted by C#'s rules. On the other hand, local functions or lambdas inside M2 would be allowed to shadow the parameter s, just like they can with other parameters today.

More interesting is the static question: should we allow the parameter list in a static member to shadow the extension parameter? The LDM is fairly split here between allowing or disallowing it. We therefore think we'll start most restrictive, disallowing the parameter list to shadow, and wait for feedback. There is a workaround for users who want to do this, as they can just declare a new parameterless extension block and declare the method in that block, so this isn't a hard blocker for code, but we'd rather start as more restrictive and loosen when we have real examples, rather than starting with a loose rule that we may regret later.

Conclusion

Extension block parameters will be lexically in scope in all members declared within the block, and will be treated as if they were declared in the parameter list of each extension member for the purposes of naming collisions and shadowing.

Type parameter inferrability

Question: https://github.com/dotnet/csharplang/blob/82157ff229f6c1bd2954a96ec2acb47064a48bad/proposals/extensions.md#extension-declaration-validation (first bullet)

We next looked at whether we should loosen the requirement that any type parameters in the extension block declaration had to be inferrable from the extension parameter. We don't think that we have the examples that would be necessary to lift this restriction today: we can think of a couple of hypotheticals, such as an out-of-order TResult, TSource, or a set of type parameters where TSource needed to be constrained based on TResult, but we don't have any concrete examples of this. Given that, we think we should start most restrictive, and wait for users to bring examples to us.

Conclusion

We will not loosen the restriction, all type parameters in the extension block declaration must be inferrable from the extension parameter.

Accessibility

Question: https://github.com/dotnet/csharplang/blob/82157ff229f6c1bd2954a96ec2acb47064a48bad/proposals/extensions.md#accessibility

Finally today, we took a brief look at accessibility to get an initial gut feeling. The expressed sentiment in the room leaned towards private being with respect to the entire static class, not towards an individual extension block, but we did not have time to deeply dive into this topic, so no conclusions were made.