# C# Language Design Notes for Oct 22, 2018

## Agenda

Discuss two records proposals: 

1. [The existing old
one](https://github.com/dotnet/csharplang/blob/master/proposals/records.md)

2. [The data classes
proposal](https://github.com/dotnet/csharplang/pull/1667)

## Discussion

### "Nominal" records.

Nominal is more resilient to reordering or adding members. Part of the
motivation here is the experience from CompilationOptions in Roslyn, which we
accidentally broke a couple of times.

The classes that nominal records would replace are often mutable, just so
that object initializers can work. Nominal are proposed to facilitate object
initializers even for immutable ones. The trick for allowing that is a
pattern that uses an underlying builder struct. The proposal would emit
errors or warnings on object initializers that neglect to initialize
properties which aren't declared with an initializer.

We think that object initializers are not just the result of "lazy" API
design, but an initialization pattern that folks actually prefer. With many
data elements it certainly has a better tooling experience. The presence of
an accessible constructor with a (well recognized) builder at the end would
be what allows an object initializer to work. It's a bit similar to params.

For inheritance, you would make a builder per layer of inheritance, which
gets a little ugly. It might be an argument for making them unspeakable. The
proposal for builders being "striped" also builds the structure of the
inheritance hierarchy into the public surface area, so that changing the
hierarchy would be breaking under the hood.

All alternatives that we can think of also have pretty horrendous downsides.

#### Fields

The proposal translates them into ref-returning getter-only properties, and
sticks them in the builder. This would break reflection compared to today. VB
doesn't have ref returns, so it's interesting how it deals with them when it
encounters them. We need to make sure that this wouldn't degrade the VB
experience.

- [ ] Open Issue: does it break anything else?

#### Equality

Mutable data members in classes should generally not participate in equality
and hash code by default. Otherwise, there's the risk that the item gets
added to a hash table, then its hash code value changes when one of the
members gets mutated.

*Q: does this feature buy us enough to be worth the cost?*
Maybe not just for compat, because most people won't rewrite old code the new
way. It's the value to new code that's most important. That said, this is an
important opportunity for cleanup that would help people not accidentally
break themselves or their customers when they evolve.

### Positional records

Should we reserve the `class C(X x, Y y, Z z)` syntax for primary
constructors? First idea is that `data` as a modifier is necessary to make it
a positional record. But then adding data changes the meaning of the
parameter list quite radically.

### "Positional" vs. "Nominal"

The positional proposal is syntactic sugar for something that people to a
larger degree do today. The nominal is maybe more something that they wish
they could do, but don't have the expressiveness to do yet.

The positional proposal produces With methods that are so nice it might not
even be worth it to put a with expression syntax on top. For the nominal
proposal, because of the builders, you really want a syntax on top, or it
gets unsightly.

Summary of benefits of nominal over positional records:

- Object initializer syntax (could possibly be added to positional)
- Binary
compat from version to version when you move to records (positional can't) 
- Source compat

**Conclusion**

There are many components of the proposals that don't quite yet feel like
they click together, but we should keep working on that.

### Discriminated unions:

The record syntax will probably affect discriminated union design. That
doesn't mean we shouldn't keep exploring records.

Discriminated unions will also probably face the public/private API dichotomy
being explored in records: if you ever want to add more cases, you break
every consumer's exhaustiveness check.
