Add meeting notes for Feb. 19, 2020

This commit is contained in:
Andy Gocke 2020-02-19 19:44:31 -08:00
parent 33a60a1db1
commit 82e330685f

View file

@ -0,0 +1,82 @@
# C# Language Design for Feb. 19, 2020
## Agenda
Exploring Value Equality
## Discussion
Proposal: https://github.com/dotnet/csharplang/issues/3213
* We haven't decided (yet) to add support for value equality on all
classes (separate from records)
* The behavior is actually that all fields _declared_ in the class are
members in the value equality, not all fields in the class (since inherited fields are not
included)
* Inheritance would be implemented using the previously described
proposals using the `EqualityContract` property
* Records wouldn't behave differently, except that they have `value` by
default
* The main difference with how records work in other places is that the semantics
of a record is otherwise decided by the members of the primary constructor, while in this
proposal the members of the record primary constructor have no special contribution to the value
equality semantics
* There's an evolution risk where we want to provide more complex things, like deep
equality, but these features don't support enough complexity to add it. Instead, we end up just
adding more keywords or more attributes. Consider array fields. The default equality is reference
equality, but sequence equality isn't particularly rare. How would users customize that?
A new keyword? Attribute? Writing Equals manually?
* Turns out we're finding a lot of customization pivots. String comparison is another one.
If we want to support all these scenarios attributes could be better. If we could use
attributes to supply an EqualityComparer that would be almost completely customizable.
* If equality is this complicated, should we only support simple generated equality for
records? Can we leave more complicated scenarios to tooling, like source generators?
Record equality: use the "primary" members or use all fields?
* Using all the fields is consistent with how structs work
* Using the "primary" members mirrors how the generation of `With` or other things
generated by a record with a primary constructor
* There does seem to be a possibility that after you get to a certain size, positional
records are less useful. In that case we want a path to the nominal record. If we do want the
nominal path, it's generally desirable that we want as little "record" syntax as possible.
If we choose the struct "use all the fields" approach, then we could use exactly the
same mechanism for both the "nominal" and the "positional" records.
* The nominal record syntax that has been floated is
```C#
record Point { int X; int Y; }
```
which generates
```C#
record Point
{
public int X { get; init; }
public int Y { get; init; }
}
```
Aside from the shorthand for properties, this generates Equals, GetHashCode and some form
of "With", which doesn't seem much different from proposals for a separable value equality. Is
there really much point in separating these proposals?
* One completely opposite possibility: bypass the question by prohibiting private members in the
positional record entirely
**Conclusion**
No hard decisions yet. Leaning slightly towards using "all declared fields" as the metric for
value equality. There's some support for the "no private fields approach."