Docs: Records intro in what's new page can cause confusion/misunderstanding

Created on 12 Sep 2020  Â·  12Comments  Â·  Source: dotnet/docs

C# 9.0 introduces record types, which are a reference type that provides synthesized methods to provide value semantics for equality. Records are immutable by default.

Record types make it easy to create immutable reference types in .NET.

Records in general doesn't seem to ensure immutability in any way. This is very specific to positional records only.


Document Details

⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.

Area - C# Guide Technology - C# What's New P2 Pri2 csharp-whats-netech doc-bug dotnet-csharprod

Most helpful comment

I also think immutability should be mentioned. The primary constructor is a key difference between a record and a class, and when using only a primary constructor, records are immutable. Even without out, personally I find myself using records mainly for immutability features (init accessors and withers), and rarely for their value equality.

Yes I realize classes can use init accessors too, but given this is a whats new page, I think writing it from the point of view of existing code where classes don't have init accessors makes sense.

If immutability should be mentioned, the doc should be very clear that records doesn't mean or guarantee it, and only simple positional records (i.e. record MyRec(whatever, ....); and not record MyRec(whatever, ...) { // extra fields/properties }.

It should also mention that even simple positional records doesn't provide deep immutability. (which may come in future C# versions)

All 12 comments

Good point @Youssef1313

I'd like to keep this article brief, so some nuances are not covered. But, it shouldn't be misleading The reality is even more subtle: a developer can add additional members, even when using primary constructors. Therefore, even positional records aren't guaranteed to be immutable.

How about this for alternative wording:

C# 9.0 introduces record types, which are a reference type that provides synthesized methods to provide value semantics for equality. Record types make it easy to create immutable reference types in .NET. Record types are immutable, unless hand written members allow mutation.

@BillWagner This is more clear and less misleading, but I'm not sure whether immutability should be ever mentioned or not.

I think immutability should be mentioned. It's one of the reasons why a developer would choose a record instead of a class. (Value semantics being the other reason).

The difference I can see between a class and a record is value equality being added by default, and other synthesized methods such as PrintMembers and Clone which are irrelevant to immutability.

Besides those, I see that a record is nearly identical than a class.

Not sure if I'm missing something. I haven't played enough with records.

Value semantics being the other reason

@BillWagner what do you mean by "value semantics"? Whenever I see "value semantics", I think about distinction between variables and their copying of value types and reference types. From the value types article:

A variable of a value type contains an instance of the type. This differs from a variable of a reference type, which contains a reference to an instance of the type. By default, on assignment, passing an argument to a method, and returning a method result, variable values are copied. In the case of value-type variables, the corresponding type instances are copied.

As records are classes, I assume record variables still follow reference-type semantics. Is that correct?

If you mean by "value semantics" something different, would it be possible to find another term for that? In general, would be ideal to avoid using the word "value", as it's overloaded with various meanings and may be more confusing than helping.

Uh... now I see you mean "value semantics for equality". Now, in the docs that's just called "value equality":
https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/statements-expressions-operators/equality-comparisons#value-equality

Should we keep using that term ("value equality")?

Thanks @pkulikov Yes, "value equality" is the correct term.

@BillWagner @Youssef1313 what about this take:

C# 9.0 introduces record types. A record type is a reference type that provides compiler-generated methods to support value equality. By default, record types are immutable, but you can define members that support mutation.

(Main motivation is to avoid "synthesized" and "hand written" terms; in the docs, "user-provided" or "user-defined" is usually used instead of "hand-written". Also, with source generators, those can be not hand-written, but still user-provided, I guess).

Immutability would be a great trait to associate with records but I'm afraid that it can't really be mentioned more than in passing, and very specifically with positional records, without leaving a very misleading impression as to what the feature provides. The difference between an otherwise identical record and class is little more than value equality.

I also think immutability should be mentioned. The primary constructor is a key difference between a record and a class, and when using only a primary constructor, records are immutable. Even without out, personally I find myself using records mainly for immutability features (init accessors and withers), and rarely for their value equality.

Yes I realize classes can use init accessors too, but given this is a whats new page, I think writing it from the point of view of existing code where classes don't have init accessors makes sense.

I understand, and in the context of positional records then immutability makes sense. But we're already seeing confusion on the C# repository, Gitter, Discord and Twitter regarding records and immutability. With immutability being the headlining feature of records here and in the documentation and repeated across the infinite blogs that take those docs as gospel, having to respond that records aren't immutable except in a narrow case is a very unsatisfying answer.

If you want these docs to claim that records are immutable, I think it would be better to open with simple positional records only, then expand into nominal records and how init-properties are what actually enable the immutability and how the remaining features of records (value equality and withers) make their consumption easier. The current first example is quite literally no different than the class version of an immutable reference type despite claiming that record reduces the boilerplate of making that type immutable.

It would be good to word it so that no one can come away thinking "if I see a record, I know it's immutable."

(Positional or otherwise)

I also think immutability should be mentioned. The primary constructor is a key difference between a record and a class, and when using only a primary constructor, records are immutable. Even without out, personally I find myself using records mainly for immutability features (init accessors and withers), and rarely for their value equality.

Yes I realize classes can use init accessors too, but given this is a whats new page, I think writing it from the point of view of existing code where classes don't have init accessors makes sense.

If immutability should be mentioned, the doc should be very clear that records doesn't mean or guarantee it, and only simple positional records (i.e. record MyRec(whatever, ....); and not record MyRec(whatever, ...) { // extra fields/properties }.

It should also mention that even simple positional records doesn't provide deep immutability. (which may come in future C# versions)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sebagomez picture sebagomez  Â·  3Comments

sime3000 picture sime3000  Â·  3Comments

ite-klass picture ite-klass  Â·  3Comments

FrancescoBonizzi picture FrancescoBonizzi  Â·  3Comments

garfbradaz picture garfbradaz  Â·  3Comments