# C# Language Design Meeting for October 20th, 2021

## Agenda

1. [Open questions in list patterns](#open-questions-in-list-patterns)
    1. [Types that define both Length and Count](#types-that-define-both-length-and-count)
    2. [Slices that return null](#slices-that-return-null)
2. [Primary constructors](#primary-constructors)

## Quote of the Day

- "No fingerprints today, I always struggle with it after a bank robbery, when I file them down"

## Discussion

### Open questions in list patterns

https://github.com/dotnet/csharplang/issues/5137

We had 3 open questions from tests on list patterns. Questions 1 and 2 both relate to types with both `Length` and `Count` properties, so our decision
applies to both.

#### Types that define both Length and Count

Our previous definition of a type that can be matched by a list pattern is that the type must be both indexable and countable. Because countable could be
one of two properties, `Length` or `Count`, we need to decide what do when a type has both. Our options are:

1. Treat them as equivalent and assume they return the same value. This will affect subsumption.
2. Treat the non-recognized one (`Count` in the case where both `Length` and `Count` are defined) as not being special at all.

Conceptually, we think it would be odd to assume that `Count` is equal to `Length`, even though we'll never use it for any form of slicing or length checking.
While it might be reasonable to assume they return the same value, we don't think it's an important scenario. We'll have nearly a year of preview on this
feature, so we have plenty of time to react to feedback if dogfooding shows that it's an important scenario.

##### Conclusion

We will not treat `Length` and `Count` as being connected when both are defined.

#### Slices that return null

We believe that well-defined slice methods should never return `null` for an in-bounds range, and we'll never generate a call to such a slice method with
an out-of-bounds range. However, we also don't think there's a customer for this scenario: a search of GitHub showed no `Slice` methods that return an
annotated value, and treating a slice method differently than its annotation would require both implementation effort and customer education. Given that
there are no known cases this affects, we don't think it's worth it. Similarly to the first question, if such scenarios are identified during preview, we
can correct appropriately.

##### Conclusion

If a `Slice` method is annotated, we will treat it as potentially returning `null` for the purposes of subsumption and exhaustiveness.

### Primary constructors

https://github.com/dotnet/csharplang/issues/2691

Now that records have been out for a year and we've expanded them to struct and reference types, we think it's time to start looking at primary constructors
again. We updated the proposal with the new syntax forms from our records work, removing or modifying components where they make sense. Unlike for records,
primary constructors aren't about defining the members that make up a grouping of data: instead, they're purely for defining the inputs to a class. So things
like deconstruction, equality, and public properties aren't automatically generated from the parameters. Instead, they become fields, that are then eliminted if
the field is never used outside of a field initializer.

We think there are a couple of open discussion topics:

1. Should the fields be readonly or not?
2. How important are primary constructor bodies for a generalized feature?

For question 1, we think that, for better or for worse, C# is a mutable-by-default language. We were able to change the defaults for `record` types because
mutability in a value-based reference type is actively harmful, but we have to consider a number of naming and mutability issues we were able to skirt around
in record types. Field naming conventions, for example, are heavily split in C#, with some users using a leading `_`, and some preferring to just use pascalCase
with no leading modifiers. We think `readonly` is similar: if users would like to modify the defaults of C#, they can define their own field and do so. If this
proves to be the wrong default we can make a change before it ships for real, or potentially invest in https://github.com/dotnet/csharplang/issues/188 to allow
putting modifiers on parameters.

For question 2, we think that it will be important, but that once https://github.com/dotnet/csharplang/issues/2145 is in the language, a good portion of
initialization code will be expressable in just a single initialization expression. It will miss some more complex scenarios, but we think just primary constructors
are a good first step.

In general, we also want to make sure we're defining the difference between primary constructors and required properties well. With the potential for multiple new
initialization features to ship in a single language version, we want to make sure they complement each other well. We think required properties work well for
public contracts: DTOs, POCOs, and other similar, nominal data structures that will expose these properties externally. Primary constructors, on the other hand,
are for other types, that do not define public surface area based on their parameters. Instead, they simply define input parameters, and can assign them to private
fields or otherwise manipulate them as they choose.

Some concrete feedback on the proposal:

* The exception for calling `this` for copy constructors feels premature, as they don't mean anything to any type except record types. If we generalize `with` in
the future, then the exception will make sense, and we can add it then.
* We should disallow methods with the same name as primary constructor parameters. This is confusing and while it could potentially be understandable code if the
parameter was never captured, could then have spooky action at a distance if the parameter was accidentally captured when a user forgot to write the `()` of the
method name.

#### Conclusion

These words are accepted.
