From 82e330685f18eb1fd1af98b9d6e53e4cd72b87a7 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Wed, 19 Feb 2020 19:44:31 -0800 Subject: [PATCH] Add meeting notes for Feb. 19, 2020 --- meetings/2020/LDM-2020-02-19.md | 82 +++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 meetings/2020/LDM-2020-02-19.md diff --git a/meetings/2020/LDM-2020-02-19.md b/meetings/2020/LDM-2020-02-19.md new file mode 100644 index 0000000..c75b983 --- /dev/null +++ b/meetings/2020/LDM-2020-02-19.md @@ -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."