What Is The Purpose Of A Record Struct?
Asked Answered
W

1

16

C# 9 added the record type, which is a new reference type that uses value-based equality.

C# 10 introduced the record struct syntax to define a value type with similar properties to record (https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/record).

It seems unusual to create a value type version of a type that was created to be a reference type that also has value-based equality - that would surely remove most of the benefit of using the type.

Why would you ever want to declare a record struct?

Is there something more that I am missing?

Windproof answered 22/12, 2022 at 18:6 Comment(15)
Another SO thread might help a bit #64817214Lytta
Check this article: nietras.com/2021/06/14/csharp-10-record-struct (note also that record struct is not immutable. readonly record struct is)Establishment
@NirmalSubedi already checked, it doesn't help as I'm talking about a record struct not a plain record or structWindproof
Read the article from Evk, and check the second code snippet. That's alone enough to introduce this. That's a very common code construct, and removing tons of boilerplate code is a plus. But see also this article - there are lots of other tiny, seemingly irrelevant, additions, which when gathered together form a very handy tuple-like utility, more handy than the current several tuple types.Sherrill
@Sherrill the second code snippet doesn't really justify a meaningful purpose for record struct. Using a new type just to reduce code isn't really sensible- improved syntax would make more sense. Also since tuples exist, shortening code is not really a good reason to use record struct. Will study the rest of the articles to see what else there is.Windproof
"Using a new type just to reduce code isn't really sensible- improved syntax would make more sense." But that's exactly what record does. It does not introduce new types, it introduces a new way to write class and struct declarations with autogenerated boilerplate. Mere syntax cannot be retrofitted to make existing classes or structs behave this way, that would be far too complicated -- and changing how tuples work, while possible in principle, is a passed station since large amounts of existing code count on their existing behavior.Melodee
@JeroenMostert false, record has different properties to class and struct. It is not just a way of declaring existing types with autogenerated code. Also there are many cases where new syntax and functionality has been added with existing types (usually using keyword to modify behaviour) so I'm not sure what you mean.Windproof
Well, I'm not sure what you mean. Every record class is a class. Every record struct is a struct. (A plain record is equivalent to record class.) All .NET languages are capable of consuming records, even if they have no explicit support for them, precisely by virtue of the fact that records do not extend the .NET type system. It is possible to write types that behave identically to any given record declaration, with the only difference being that your members would not have a [CompilerGenerated] attribute.Melodee
OK, I guess I need to walk that statement back a little bit -- a with expression only works with records specifically because it looks for a compiler-generated Clone method. Since you can't declare such a method yourself, this is the one aspect where records are distinguishable from non-records on the language level. (Although this argument specifically only applies to record classes and does not apply to record structs, since with works on all structs.)Melodee
@JeroenMostert according to the docs record is a new reference type, record class is the same plain record - the syntax just makes it clear that it's reference type. record struct is a record that is value type: learn.microsoft.com/en-us/dotnet/csharp/whats-new/tutorials/…Windproof
All structs are value types, so yes, that obviously includes record structs as well. And indeed, record is the same thing as record class now. Nothing of that invalidates what I said. The docs are misleading to the point of being incorrect when they talk of records as "a new reference type that you can create instead of classes or structs"; records wouldn't be half as useful if they weren't also plain old classes to existing code! Value-based equality and immutability can be implemented on classes manually, it's just tedious. record eliminates this tedium.Melodee
Correct. Record-struct is a value-type. ref - note how in "C# 9 introduces records, a new reference type that you can create instead of classes or structs. C# 10 adds record structs so that you can define records as value types. Records are distinct from classes in that record types use value-based equality. " the first sentence says RECORD, second RECORD-STRUCT and then third again refers to RECORD (not record struct). Gosh, they could have ordered those sentence a bit better.Sherrill
@JeroenMostert having had time to go through the articles, I'm starting to see what you and quetzalcoatl meant. The Microsoft documentation mislead me a bit. Will try to write an answer summarising what you've both explained with some added info from the articles.Windproof
@Sherrill beginning to understand you and Jeroen Mostert now and have added an answer. Thanks for you help, both of you.Windproof
Related: When to use record struct instead of struct, and vice versa? The real question is not "Why would you ever want to declare a record struct?", but more like "Why wouldn't you always want to declare a record struct?", because record structs are seemingly better than structs.Bombsight
W
23

The main benefits of using record struct are as follows:

  1. It allows you to simplify a struct definition to a single line
  2. It provides overloads for the == and != operators, so these can be used for comparisons with no extra code to define the operator overloads. With struct, you can only do comparisons using the Equals() method by default.
  3. It provides a more comprehensive default ToString() method than struct. The record struct ToString() method will produce the record struct name, the names of its properties and their values. The struct default ToString() method only produces the struct name.
  4. It provides performance benefits over struct

In some ways, record is similar to a value tuples which provide default operator overloads and have a ToString() method that is closer to record struct (value tuples' ToString() method produces the values of all of their properties).

However, value tuples are only used on the fly, whereas record struct can be used to define type that will be repeatedly used.

Note

record / record class is immutable by default but record struct is not, so if you want an immutable record struct, you must use readonly record struct.

Final Remark

Considering the benefits of using record struct over struct, it's probably best to always prefer record struct unless there is some very specific reason not to.

It seems that record struct is an enhancement of struct, leaving the old type so that existing behaviour/functionality of struct is not removed.

Windproof answered 28/12, 2022 at 11:52 Comment(4)
FYI, for those that stumbled upon this post like I did: The performance increase is only apparent if you DON'T implement IEquatable<T> and GetHashCode on your struct. This is even mentioned in the benchmark. Also, you may get a very, very, slight performance improvement if you implement things on struct yourself. The actual page for the benchmark is here: nietras.com/2021/06/14/csharp-10-record-struct So, my recommendation is to use whatever is most convenient for you and your needs (e.g. performance/control, use a struct, otherwise use a record)Infect
@Infect my aim was not to encourage its use but more to find reasons for its existence and state them. As always , one should weight up their needs and choose what's best instead of automatically trying to optimise everything they can possibly think ofWindproof
"up to 20 times faster" - ha-ha, so journalist-like-click-baity. But we all know that this most probably refers to equality comparison only since for regular structs it uses reflections which is obviously slow.Guayule
@Guayule yes, I think I'll remove the actual figures because I'm not sure of them. it's probably a very specific scenario.Windproof

© 2022 - 2024 — McMap. All rights reserved.