2018-10-26 22:07:49 +02:00
|
|
|
# C# Language Design Notes for Oct 22, 2018
|
|
|
|
|
|
|
|
## Agenda
|
|
|
|
|
2018-11-13 19:56:39 +01:00
|
|
|
Discuss two records proposals:
|
|
|
|
|
|
|
|
1. [The existing old
|
2018-10-26 22:07:49 +02:00
|
|
|
one](https://github.com/dotnet/csharplang/blob/master/proposals/records.md)
|
2018-11-13 19:56:39 +01:00
|
|
|
|
2018-10-26 22:07:49 +02:00
|
|
|
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:
|
|
|
|
|
2018-11-13 19:56:39 +01:00
|
|
|
- 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
|
2018-10-26 22:07:49 +02:00
|
|
|
|
|
|
|
**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.
|