From 99094464ff7870730272e766facce52cc035a4f4 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Wed, 19 Feb 2020 20:35:39 -0800 Subject: [PATCH] Add LDM notes for Feb. 12, 2020 --- meetings/2020/LDM-2020-02-12.md | 116 ++++++++++++++++++++++++++++++++ meetings/2020/README.md | 20 +++--- 2 files changed, 128 insertions(+), 8 deletions(-) create mode 100644 meetings/2020/LDM-2020-02-12.md diff --git a/meetings/2020/LDM-2020-02-12.md b/meetings/2020/LDM-2020-02-12.md new file mode 100644 index 0000000..edc0600 --- /dev/null +++ b/meetings/2020/LDM-2020-02-12.md @@ -0,0 +1,116 @@ + +# C# Language Design for Feb 12, 2020 + +## Agenda + +Records + +## Discussion + +### Value equality + +Proposal: use the `key` keyword previously mentioned, but also +require it on the type declaration as well, e.g. + +```C# +key class HasValueEquality +{ + public key int X { get; } +} +``` + +There are a number of things we could pivot on + +```C# +key class HasValueEquality1 { public key int X { get; } } +class HasValueEquality2 { public key int X { get; } } +key class HasValueEquality3 { public key X { get; } } +class HasValueEquality4 : IEquatable { public int X { get; } } +``` + +---- + +```C# +record Point1(int X); // Implies value equality over X +record Point2a(int X); // Implies inherited equality +key record Point2b1(int X); // Implies value equality over X +key record Point2b2a(int X); // Implies "empty" value equality +key record Point2b2b(key int X); // Implies value equality over X + + +key class Point3a(int X); // implies record + value equality over X +data class Point3b(int X); // implies record with inherited equality +``` + +#### Equality default + +We originally considered adding value equality on records both because it's difficult to +implement yourself and it fits the semantics we built for records in general. We want to validate +that these things are still true, and new considerations, namely whether it is the appropriate +default for records and whether it should be available to other types, like regular classes. + +We left off in the previous discussion asking whether value equality is not just +an inconvenient default, but actively harmful for key scenarios for records. Some examples +we came up with are either classes with large numbers of members, where value equality may +be unnecessary and slow, and circular graphs, where using value equality could cause +infinite recursion. + +These do seem bad, but it's not obvious that these scenarios either fit perfectly with the +canonical record, or if the consequences are necessarily worse than default reference equality. +Certainly producing infinite recursion in object graphs is bad, but silently incorrect behavior +due to inaccurate reference equality is also harmful, in the same sense. It's also easier +to switch from value equality to reference equality than it is to switch from reference equality +to value equality, due to the complex requirements in a value equality contract. + +**Conclusion** + +Value equality seems a reasonable default, as long as they are immutable by default, and that +there is a reasonable way to opt-in to a different equality. + +#### Separable value equality + +Given that we like value equality as a default, we have to decide if we want a separable equality +feature as well. This is important for the scenario: + +```C# +record Point1(int X) +{ + public int X { get; } +} +``` + +if there's a separate `key` feature, we need to decide if the substituted property should +require, allow, or disallow the `key` modifier, e.g. + +```C# +record Point1(int X) +{ + public key int X { get; } +} +``` + +We also need to decide what such a "separable" equality feature would look like, and if it has a +difference between records and other classes. We could add a `key` feature for non-records, and +disallow `key` entirely in records. The members of a record equality would then not be +customizable. + +The individual `key` modifiers on non-records seem deceptively complicated. + +A common case is "opt-in everything". `key` modifiers wouldn't improve much on this, as they +would be necessary on every element. On the other hand, there are often computed properties that +may be seen as part of "everything", but not part of the equality inputs. The plus of record +primary constructors is that they identify the "core" inputs to the type. + +Individual `key` modifiers also do not help with the large custom classes that are written today +where it's easy to forget to add new members to equality. With a `key` modifier you can still +forget to add the modifier to a new member. + +These decisions play into records as a whole because they affect the uniformity of record and +non-record behavior. If records are defined by their "parameters", namely in this syntax the +primary constructor parameters and identically named properties, then no other members should +be a part of the equality. However, that would imply members in the body are not automatically +included. For regular classes, it seems backwards. Members are not generally included, they have +to be added specifically. + +On the other hand, if we prioritize uniformity, general members in record bodies would be included +in equality, which would harm a view of records as consisting primarily of the "record inputs." \ No newline at end of file diff --git a/meetings/2020/README.md b/meetings/2020/README.md index 9688379..c186612 100644 --- a/meetings/2020/README.md +++ b/meetings/2020/README.md @@ -26,14 +26,6 @@ - https://github.com/dotnet/csharplang/issues/3213 Natural value equality (Mads) - https://github.com/dotnet/csharplang/issues/3137 Records (Mads) -## Feb 12 - -- https://github.com/dotnet/csharplang/issues/3137 Records (Mads) - -## Feb 10 - -- https://github.com/dotnet/csharplang/issues/3137 Records (Mads) - ## Jan 29, 2020 - Records: drilling in to individual features (Mads) @@ -46,6 +38,18 @@ Overview of meetings and agendas for 2020 +## Feb 12 + +[C# Language Design Notes for Feb. 12, 2020](LDM-2020-02-12.md) + +Records + +## Feb 10 + +[C# Language Design Notes for Feb. 10, 2020](LDM-2020-02-10.md) + +Records + ## Feb 5 [C# Language Design Notes for Feb. 5, 2020](LDM-2020-02-05.md)