# C# Language Design Meeting for May 8th, 2023

## Agenda

- [Primary Constructors](#primary-constructors)

## Quote of the Day

- "Depending on how you interpret it, the results can be whatever you want"

## Discussion

### Primary Constructors

https://github.com/dotnet/csharplang/issues/2691  
https://github.com/dotnet/csharplang/discussions/7109#discussioncomment-5666621

Today we looked at one of the pieces of community feedback for primary constructors, around name shadowing from base types. A user might not
expect the output that this program will give:

```cs
public class Base
{
    protected readonly string a = "base";
}

public class Derived(string a = "derived") : Base
{
    public void M()
    {
        Console.WriteLine(a);
    }
}
```

This code will print `base` when `Derived.M()` is called, because the base field shadows the primary constructor parameter. While this could be confusing
for this particular case, we don't think this is common case for this type of code; instead, the common case is something more like the following:

```cs
public class Base(string a)
{
    protected readonly string a = a;
}

public class Derived(string a = "derived") : Base(a)
{
    public void M()
    {
        Console.WriteLine(a);
    }
}
```

In this example, `a` is passed through to `Base` via its constructor, and the protected field is referenced by the derived type ensuring that the value
is not double-stored. There are a few possible options we can look for improving the first scenario:

1. Warn whenever a base member shadows a primary constructor parameter at the use site. This would produce a warning in both of the above code samples.
2. A variation on 1, produce a warning whenever a base member shadows a primary constructor parameter and that parameter wasn't passed to the base type.
   There are 2 subvariants of this:
   1. Ensure that names match when doing this. IE, passing `a` to a parameter named `b` would not count for the purposes of suppressing the warning.
   2. Do no validation on the name of the parameter.
3. Change the shadowing order: make the primary ctor parameter shadow the base member, so accessing the base member would require `base.` qualification.

For 1, we're concerned about the impact to the second code example: that seems the far more common case in the wild, and impacting it negatively isn't
great. For 3, we're unsure whether the effective behavior being different than records will be confusing: `Derived` would not create a new member named
`a`, it would use the existing one from the base. This leaves us with option 2.

For 2, we thought a bit about the subvariants. We're a bit concerned by field naming conventions differing from parameters: what guarantees are there
that a constructor parameter named `a` will actually assign to a field named `a`? There are none, of course, only long-standing conventions. Some
users prefer to name their fields with `_` prefixes (following the C# code-style guidelines), but many keep them exactly the same. We ultimately think
that there's enough signal of intent in passing the primary ctor parameter, no matter what the name of the base ctor parameter is, and we can suppress
the warning for this case.

#### Conclusion

Option 2.2: Produce a warning on usage when a base member shadows a primary constructor parameter if that primary constructor parameter was not
passed to the base type via its constructor.
