# C# Language Design Meeting for October 5th, 2020

## Agenda

1. [`record struct` primary constructor defaults](#record-struct-primary-constructor-defaults)
2. [Changing the member type of a primary constructor parameter](#changing-the-member-type-of-a-primary-constructor-parameter)
3. [`data` members](#data-members)

## Quote of the Day

- "The problem with people who voted for immutable by default is that they can't change their opinion. #bad_dad_jokes"

## Discussion

### `record struct` primary constructor defaults

We picked up today where we left off [last time](LDM-2020-09-30.md#primary-constructors-and-data-properties), looking at what
primary constructors should generate in `record struct`s. We have 2 general axes to debate: whether we should generate mutable
or immutable members, and whether those members should be properties or fields. All 4 combinations of these options are valid
places that we could land, with various pros and cons, so we started by examing the mutable vs immutable axis. In C# 9, `record`
primary constructors mean that the properties are generated as immutable, and consistency is a strong argument for preferring
immutable in structs. However, we also have another analogous feature in C#: tuples. We decided on mutability there because it's
more convenient, and struct mutability does not carry the same level of concern as class mutability does. A struct as a
dictionary key does not risk getting lost in the dictionary unless it itself references mutable class state, which is just as
much of a concern for class types as it is for struct types. Even if we had `with` expressions at the time of tuples, it's
likely that we still would have had the fields be mutable. A number of C# 7 features centered around reducing unnecessary struct
copying, such as `readonly` members and ref struct improvements, and reducing copies in large structs by `with` is still a
useful goal. Finally, we have a better story for making a `struct` fully-`readonly` with 1 keyword, while we don't have a similar
story for making a `struct` fully-mutable with a similar gesture.

Next, we examined the question of properties vs fields. We again looked to our previous art in tuples. `ValueTuple` can be viewed
as an anonymous struct record type: it has value equality and is used as a pure data holder. However, `ValueTuple` is a type
defined in the framework, and its implementation details are public concern. As a framework-defined pure data holder, it has no
extra behavior to encapsulate. A `record struct`, on the other hand, is not a public framework type. Much like any other user-
defined `class` or `struct`, the implementation details are not public concern, but the concern of the creator. We have real
examples in the framework (such as around the mathematics types) where exposing fields instead of properties was later regretted
because it limits the future flexibility of the type, and we feel the same level of concern applies here.

#### Conclusion

Primary constructors in `record struct`s will generate mutable properties by default. Like with `record` `class`es, users will
be able to provide a definition for the property if they do not like the defaults.

### Changing the member type of a primary constructor parameter

In C# 9, we allow `record` types to redefine the property generated by a primary constructor parameter, changing the accessibility
or the accessors. However, we did not allow them to change whether the member is a field or property. This is an oversight, and
we should allow changing whether the member is a field or property in C# 10. This will allow overriding of the default decision
in the first section, giving an ability for a "grow-up" story for tuples into named `record struct`s with mutable fields if the
user wishes.

### `data` members

Finally today, we took another look at `data` members, and what behavior they should have in `record struct`s as opposed to
`record` `classes`. We had previously decided that `data` members should generate `public` `init` properties in `record` types;
therefore, the crucial thing to decide is if `data` should mean the same thing as `record` would in that type, or if the `data`
keyword should be separated from `record` entirely. In C# today, we have very few keywords that change the code they generate
based on containing type context, and making `data` be dependent on whether the member is in a `struct` or `class` could end up
being quite confusing. On the other hand, if `data` is "the short way to create a nominal record type", then having different
behavior between positional parameters and `data` members in a `struct` could also be confusing.

#### Conclusion

We did not reach a decision on this today. There are 3 proposals on the table:

1. A `data` member is `public string FirstName { get; set; }` in `struct` types, and `public string FirstName { get; init; }` in
`class` types.
2. A `data` member is `public string FirstName { get; init; }` in all types.
3. We cut `data` entirely.

We'll come back to this in a future LDM.
