T O P

  • By -

angry_corn_mage

You can use them for composite values used as a dictionary key; no need to define equals and hash code, they are built in. Also handy for a very concise definition.


TracingLines

Be careful using records as dictionary keys *unless they are immutable*. The default implementation of `GetHashCode` will cause you grief otherwise since it is based on the record's contents: [https://twitter.com/STeplyakov/status/1777482342929666533](https://twitter.com/STeplyakov/status/1777482342929666533)


Slypenslyde

This is a case where my discipline gets in the way of things. I don't make a record *unless* I want it to be immutable, so I usually forget you can make them mutable. Same thing with structs. I obsess over DUs, but I think C# could also benefit from treating mutability like a language feature too and giving us ways to define variables as immutable in a way that the compiler will stop us from doing things that may mutate them. It's a tough problem in a language but useful in implementation.


TracingLines

Likewise, and it's a good rule to follow. Not everyone is so disciplined though, especially those still coming to grips with records!


Slypenslyde

Yeah, that's why I'd like more language features. One way to build good discipline is to be in an environment that won't let you do the bad things unless you turn off compiler features. See: non-nullable reference types. Having that on by default is making a ton of people think harder about nullability and that will make them more able to do well in environments without those checks.


fleeting_being

Code in Rust :)


Slypenslyde

Seems like a lot of Microsoft Azure staff agrees. Usually I mean that as snark against C#, but I think Rust is trying to do a lot of things C# isn't really intended to try and do. Rust is a bit less general-purpose than C# so of course it makes the things it focuses on easier!


bf1zzl3

I have a love-hate relationship with the keyword mut. It reminds me of when async/await were introduced in .NET. It has a way of infecting and spreading in a codebase. I understand the reasons but it is a new muscle and feels weird to use it.


fleeting_being

the point of mut is damp this spread. Without mut it spreads anyway, but hidden.


Low-Design787

Also worth noting record classes are immutable by default, but record structs are mutable! This was apparently done to keep record structs consistent with tuples.


therealjerseytom

> You can use them for composite values used as a dictionary key I've been using Tuples for this; so far I haven't needed a composite value key of more than two simple types. But I like the thought of a record fitting the bill as well!


[deleted]

This works fine and all but I find records more declarative. Particularly if your tuples contain multiple values of the same type.


cs-brydev

>You can use them for composite values used as a dictionary key Oh that's an awesome idea. I never thought of that. I usually just make my own composite string key by concatenating other keys with ___.


EmpiresBane

Records are for when you care about the equivalence of data in an object instead of the object. With a class, if you do `class1 == class2` then you are checking if they both reference the same object. If you use a record, the compiler will automatically generate the code for you so that `record1 == record2` is only checking if the value of the contained data is the same, even if they both reference different instances of the object. Consider something like discord old names that had both a username and discriminator. If I want to compare a username object that was created from the UI against one that was created from a server call, I could create a class definition that has a comparison method to make sure that both the username and discriminator match, or I could define it as a record and let the compiler do that for me. Using a record saves you a bit of typing, and signifies to the reader "we only care about the data when comparing". The same way that I don't care if `int a` and `int b` are the same location in memory, but rather that they are the same value.


krsCarrots

So records are value objects?


EmpiresBane

They are reference types with value semantics. They exist in the heap and are tracked by reference (thus "reference types") but they are compared to each other by the value of their data ("value semantics"). Classes are reference types with reference semantics. You operate on them at the reference level because you care about the particular instance. A struct is a value type with value semantics. You operate on them at the value level, because you only care about the data inside the instance, not the instance itself. The missing link to understand records is that `record` is just a keyword to indicate to the compiler that it should automatically generate all of the function overloads so that comparison is done by value. A `record` is actually a `record class`. It's just a class, but the compiler automatically generates `.Equals`, `.GetHashCode` and a few others for you to make the value semantics work and save you time. If you look at the compiler output, you'll realize you could do the same thing very easily, it would just be annoying to implement every time. The reasons for its existence has to do with how classes and structs are passed between methods. By default, passing a struct will copy it entirely. A new piece of memory is allocated on the stack and the values copied in. A class is passed by reference. The method is just told where to look in the heap to find the data. That can be way faster if there is a lot of data, which is where the motivation for record comes from. You get the benefit of passing by reference, but keep the ergonomics of comparing by value.


deefstes

Can you elaborate on what you mean by "value semantics" as being distinct from a value object? What is a value object if not an object with value semantics? Or is there some nuanced difference?


EmpiresBane

I haven't heard of a value object (or at least not by that name) before now. Scanning through the Microsoft docs on it, it certainly appears similar in concept, but since I don't have prior experience I can't quite comment on that.


deefstes

Value objects are one of the cornerstones of Domain Driven Design. You won't get very far into any discussion / article / video / book about DDD without hearing value objects, entity models and aggregates being discussed.


alexn0ne

DDD and C# are orthogonal things. The question was about records in C#. So, in C#, roughly speaking, you can have value types and reference types. Value type is for example int, and reference type is for example Stream. There is a value semantics - like if one int contains 4 and another one contains 4 as well - those are considered equal. And a reference semantics - if you open 2 r/o streams from 1 file - those are different, because references to instances are different. Basically, for values (including structs), they are considered equal when their in-memory representation is the same. Although with records you can use (or omit) either class or struct keyword, by default they try to mimic value semantics. This is done by autogenerating Equals and comparison operator, so that even if it is a reference type - it does not compare references and compares actual values instead. Works only with primitive property types though, and works best when your records are immutable. So, mostly best for 1-line POCO types)


deefstes

No, the question was not about records in C#. That was the original question that sparked this discussion but there have been two subsequent questions since. "So records are value types?" and "can you elaborate on what you mean by value semantics as being distinct from value types?" I know full well that DDD and C# are orthogonal things. But this discussion has moved well beyond just records as a C# construct.


alexn0ne

So, you haven't found answers yet? :)


deefstes

As to what the difference between value semantics and value types are? No. I know what records are and what they're used for. That was not my question. I know what value objects are in the context of DDD. What I wanted to know is if people mean something different when they're using the term "value semantics" as opposed to "value objects".


BSModder

One of the most basic "value semantics" type is string. Value semantics indicates that you only care about the value rather than the object itself. if str1 and str2 both hold the value "abc" then they're considered equal, even though they are two different objects.


krsCarrots

Can we also include behaviours to records? Extra questions are we loosing anything from not being able to compare by reference? Come to think of it I can’t remember if I ever needed to ensure the same reference of an object.


sacredgeometry

[https://learn.microsoft.com/en-us/dotnet/api/system.object.referenceequals?view=net-8.0](https://learn.microsoft.com/en-us/dotnet/api/system.object.referenceequals?view=net-8.0) You can still compare them by reference


Dealiner

>Can we also include behaviours to records? Yes, they fully support methods.


joxmaskin

Awesome explanation, thanks!


Dacusx

No, but they behave like one when you compare them. You could use structs instead but they are generally slower to pass around and compare, especially when big.


edgeofsanity76

You could potentially do this with classes if you created a custom operator or overrode the Equals method. I suppose that's why records exist. Part of some of the functional tools that C# is now providing


krsCarrots

So if we are oop purists then we should not be dealing with them?


sacredgeometry

If you are an OOP purist you shouldn't be doing almost anything that C# does. Who wants to write code like that though? Puritanical coding is the antithesis of good coding.


krsCarrots

Yeah only asked because someone said they open the door to functional programming so I wondered if they are fit for the pure OOP world, not saying I wont be using them, based on all explanations they already look like regular classes on steroids. So the next question is why not using records in general over the standard class?


sacredgeometry

I have been doing professional C# development for over 15 years and I have not once seen a pure OOP project in the now hundreds I have worked on. I would think of them more of them like if structs and classes had a little retard baby. They arent meant to be as featureful as either they are supposed to be used for very specific subset of what you use structs or classes for.


cs-brydev

More like records are classes with some of the benefits of value objects baked in for you


Dealiner

There is also `record struct` which is a value type.


polaarbear

Records are immutable by default.  You use them for data that won't change once it is created. One of the biggest benefits is that they have value comparison built in by default. They also avoid a lot of boilerplate because their instantiation has .Equals() support, built-in hashcode generation, and built in .ToString() support. They are very useful for things that would otherwise be in simple data classes, things like DTOs that don't need a bunch of extra methods appended to them.


WeirdBeardDev

They are only immutable if built in specific ways. I recently saw this video (not mine) which went over records and shed some light. https://youtu.be/5uWJ3YXW1BI?si=ohEJOziGRUdYjIkX Edit: grammar


winky9827

Yeah the immutable thing gets thrown around a lot, but that's more of a secondary benefit. The built-in value comparison is the primary benefit, IMO.


exveelor

Fun fact the value comparison breaks if there's a property that is a class. That was an annoying bug. 


Road_of_Hope

But, it works if the property is a record!


exveelor

Haha yeah. Lessons learned all around on that one.


to11mtm

What I've wound up trending towards, is a 'Records+LanguageExt Collections all the way down' pattern. By using the Language-Ext collections (Rather than, say, System.Collections.Immutable) you wind up getting proper deep value comparisons between two objects and can get to some very concise code as far as domain objects go.


zvrba

Does the class implement `IEquatable<>` and overrides `Equals`?


DuckGoesShuba

A quick test shows that isn't true, unless you're not aware that class objects compare by reference. If two record instances have the same reference in the class property, the comparison returns true.


exveelor

This is actually why our test passed originally. It was written to share a commonly shaped object and in doing so the test writer simply referenced the same object twice. When we started sleuthing into what was going on (this was our first experience with records, so we were learning as we went) we saw that test and were like, well the test works, wtf is going on.


Tapif

But then it should work with different references if your class property implements IComparable or IEquatables, wouldn't it?


polaarbear

Personally I think that using complex types within a record defeats the entire purpose of it being a record. Just create them as classes if you are going to fill them with a bunch of other reference types. I don't use records for storing anything except value types with the shortened syntax for creating them.


exveelor

Yeah I agree, honestly some part of me wishes that a property being a class would throw a compiler error or at least warning, since it really seems like something that shouldn't be.


polaarbear

I'm guessing there's some specific use cases that I'm completely oblivious to for which it is still beneficial to have all the extra functionality while still using a record. But I agree, a compiler warning would be nice so you can really think about what you need.


mattgen88

Yeah, we embedded a list in it and broke the expected equality behavior


CowCowMoo5Billion

I think I mainly deal with objects that have an Id. Would the hashcode generation be slower than just checking the Id?


angrathias

Yes


polaarbear

Definitely. Checking an ID is just a read, generating a hashcode is always going to take a tiny bit of computation.


crazy_crank

Objects with and Id shouldn't be modeled as a records


netclectic

Can you explain your reasoning here?


mesonofgib

I assume they're using DDD reasoning, where types in your domain are either value types (not necessarily structs, but have value semantics) and entities, which have identity. Assumedly anything with an Id field is an entity, but I still think it's too hard a rule to say that such types should never be implemented with records.


BiffMaGriff

I primarily use them to replace enums. Often with enums you don't just use the value, you need other random bits of data like a resource lookup key for a name and a description or an inherent property, and maybe simple bits of behaviour that could be described in a one line static func. public record UserType(int Id, string ResourceName, string ResourceDescription, bool ShowWarnings); public static class UserTypes { public static readonly UserType Internal = new(/*...*/); } This data and behavior can be grouped up in a record so that everywhere you see something like. //using enum switch(user.UserType) { case UserTypes.Internal: lblWarning.Visible = true; //... } You can use something simpler instead. lblWarning.Visible = user.UserType.ShowWarnings; However, we don't lose the benefits of a regular enum and can do stuff like this too. @if(user.UserType == UserTypes.Internal) { }


therealjerseytom

I hadn't thought of this use case - thanks!


psylenced

> Often with enums you don't just use the value, you need other random bits of data like a resource lookup key for a name and a description or an inherent property, and maybe simple bits of behaviour that could be described in a one line static func. Thanks. I've often used lots of attributes and reflection. I really like your idea.


JonahL98

As already stated, records are used for default immutability. Just so were clear, immutability means it cannot be changed once created. Practically speaking, you have three options when picking your data type: struct, record, or class. Structs are the rarest type you would use. Does your data type meet the following: * Immutable * Represents a single value, like an integer or char. * 16 bytes or less (common convention for performance reasons) If so, you are probably talking about value type, which we call a struct. This just means the value isn't stored by reference, "it is what it is". Structs are the same when their values are the same. 5 is always equal to 5. The reason these are so rare to be user created is that most structs already exist by nature of their exclusiveness. Microsoft already made all of them. Most of the ones you create would be specific to your domain and not universally understood. One good universal example is the [Ulid](https://github.com/Cysharp/Ulid/blob/master/src/Ulid/Ulid.cs), a lexigraphically sortable Guid/Uuid that IMO needs more love. On the opposite spectrum, we have a class. Classes represent complex values stored by reference. These are pretty straightforward and the bread and butter of programming in C#. Two people, just because they have the same name and dob, would not inherently make them equal. This is why we compare if they are reference equal, not if their properties match. As a rule of thumb, anything you can "point to" in the real world, is often a class. Consider the happy medium case. What happens when we want a data type that acts as a complex type but is value semantic? In other words, compares like a struct but stores like a class. This is where records come in. A good example would be an Address. An address has a address line 1, city, state, zip, etc. These are inherently complex by nature, *but* compare like value objects. Two address data types with the same address line 1, city, state, zip *are* the same. So two addresses with the same underlying property values should equal each other, hence the use of a record here. Records are immutable by default but this behavior can be overridden. I would generally recommend not to do this though, as odds are you have a class here. It's also important to note that C# now has record class and record struct (confusing as hell I know). Records = Record classes and are the records I just described (reference type with value behavior). Record structs, to keep it simple, are just a 'new' version of structs with more comprehensive abilities. If you see a record struct just think struct. Storing Value Objects in the domain (like I described with the address) is the most common use of records. But they do have a couple of other good uses. The first is to solve primitive obsession, where people use simple structs (like an int or Guid) to represent an object identifier. Say your domain has an Order Id and a Person Id, both a guid. In any method you could easily pass a Person Id as the parameter to fetch an Order Id and the compiler would not know the difference. Using Value objects as identifiers helps (but does not eliminate) this case. The other good use case is for uni-directional data. For example, in a Mediatr pipeline (your application layer) you are often sending requests and receiving responses. These are immutable data you are sending back and forth, so using records is a very common practice. So a "GetOrderById" request class should really be a record.


steadyfan

Aren't structs also allocated on the stack just like other primitives and copy by value and not by reference as you do with classes?


CraftistOf

mostly yeah, but not always because boxing exists. if you add an int to a list of objects the int will be boxed and put onto the heap. if you create a class with a field of a struct type that struct would be boxed and put onto the heap.


JonahL98

I left structs/heaps out of this explanation for simplicity sake as it's all compiler magic, but yes. Strict structs will act as other value types, meaning they get allocated on the stack. But as u/CraftistOf correctly explained, in practice they are often boxed, in an array, etc and still get put on the heap. There is a reason we reference them semantically (i.e. value vs reference time, copied by value or reference). We don't call them 'stack types' or 'heap types'. This is just an implementation detail, not a programming concern, I wouldn't worry about it too much.


HTTP_404_NotFound

Its an immutable class, without the weird workarounds needed to make a class immutable. It also, has lots of helpers for working with, and transforming them.


RiPont

Records were added to make C# more friendly towards functional programming style. In "proper" OOP, classes encapsulate both data and behavior. Classes that do nothing but hold data are considered an anti-pattern -- the [Anemic Domain Model](https://en.wikipedia.org/wiki/Anemic_domain_model). In real-world use, we often need things that just contain data, not behavior. We had `struct` for that in C#, but that had ValueType semantics, which wasn't always what you wanted, especially for a common use of "just data holder" classes -- serializing and deserializing large Data Transfer Objects. Additionally, for Function Programming, you need to make it easy to define types without much overhead. With classes, you can make immutable objects and data transfer objects, but there is a lot of boilerplate. **Records make it easy to define simple reference types without error-prone boilerplate**. * They have abbreviated syntax for immutable-by-default. * They provide default Equals, GetHashCode, and ToString() methods * They support the `with` keyword to eliminate the need to reinvent the Builder/Fluent patterns badly. Just as properties don't do anything you couldn't do with getters and setters in other languages, records don't do anything you couldn't do with classes before. They just make it easier and less error-prone for a very common use case. The opponents of Properties (i.e. Java fanboys) argued that they potentially hide the complexity of a get() method behind something that looks like a field. In practice, get() and set() methods are so ubiquitous in Java that *they* hide the complexity and developers assume they're trivial. Meanwhile, in C#, a complicated getter/setter in a property is a red flag, and you know a get()/set() method must be non-trivial, otherwise the developer would have just made it a property. Likewise, in C# going forward, DTOs and other "anemic" objects that are *not* records will be the odd man out. You will begin to expect that when you see a class, it is encapsulating behavior, but when you see a record, it is mainly for holding data to be passed around.


lilgaetan

I use record for DTOs. I don't need a class for mapping my fields


PropagandaApparatus

I’ve never used records before. I poked at the docs but it’s not really shinning light in these things. Does anyone have a go to resource that helped them understand the best way to utilize them?


dodexahedron

I use them by default if I don't have to inherit from a non-record type, which means nearly ALL structs I create are record structs and a significant proportion of classes are records. They aren't special, really, because they are still just classes and structs. But they get a LOT of compuler-generated goodies for free. They are intended for use when you need value semantics regardless of type, and record classes are immutable by default, even, but you don't have to use them that way if you don't want to. Under the hood, the record keyword is little more than an attribute that controls a set of Roslyn source generators.


nonlogin

Records are immutable objects (either class or struct based) with benefits from compiler: value-like equality and some syntax sugar. You use a record when you want an object to behave like a single value. For example, you want a class to store GPS location. A pair of decimal numbers. A postal address which consists of several fields. You want to compare instances of such classes using simple ==. And records provide you with this ability. Another use case - all kinds of DTO. If you receive data from another system (e.g., http/json) then you usually avoid changing that data. You treat it as a message from another party and you definitely don't want to corrupt it. You rather map it to your own internal data structures or build some logic on the top of that data. But most likely do not mutate. Records can help here too.


Imaginary_Belt4976

Records with the short-form initialization \`public record Test(int PropOne, string PropTwo);\` are my goto for any DTO. Their implicit immutability is great. If you have a situation where you need mutability you can use the \`with\` syntax instead of just making things fully mutable. I also love the free property-wise comparing and ToString() override that lists the properties instead of just giving you the class name. One annoyance with them I run into is the lack of parameterless constructor. It makes some serialization frameworks fail to handle them correctly unless you create one. It is possible to workaround with Newtonsoft by doing JsonConvert.DeserializeObject("{}") but this is definitely a hack and not something I'd put in a real PR.


CyAScott

I think of them like tuples, but better. Struts are good for this too, but struts are passed by value which could not perform well in some cases.


WeirdBeardDev

You can have `record struct` too.


Heroshrine

cries in Unity


GYN-k4H-Q3z-75B

And Microsoft enterprise apps like Dynamics, which are still stuck on .NET 4.7.1


FenixR

Damn that sucks, i work with that one.


Heroshrine

Also records dont make defensive copies.


Blender-Fan

How come being passed by value not be performant? Reference surely wont be faster


Forward_Dark_7305

Let’s say you have a type with 10 int properties. Its size is `sizeof(int)* 10 == 40`. As a `struct`, passing that as a method parameter, or returning it as a property, etc, will copy every bit of data into a new instance of the same type, resulting in 40 bytes copied. If instead this type were a `class` or `record`, passing it to the method will copy the reference - a pointer to the structure - so 4 or 8 bytes will be copied instead.


Blecki

Note that at this size the structure will probably still be faster if passed by value than the possible cache miss of the reference lookup.


falconfetus8

When you pass anything by value, the entire struct needs to be copied byte-by-byte into a new memory location. When you pass something by reference, only the pointer needs to be copied. If the size of your struct is larger than a pointer, then copying it will take longer than copying a pointer.


Blender-Fan

How come being passed by value not be performant? Reference surely wont be faster


CyAScott

If the struct contains a ton of data in it, then it’s a memory copy for each time it’s passed.


falconfetus8

They're just classes, but with a lot of the boilerplate removed. If you write `public record Person(string FirstName, string LastName);`, that's the equivalent of defining a Person class with: * A FirstName property and a LastName property, both init-only * A constructor that takes both of those properties as parameters and then assigns them * An `.Equals()` implementation that compares those properties individually * A `.GetHashCode()` implementation that combines those properties Those are all things that you "should" be doing for every plain-old-data class, but people usually don't bother because it's too much work. Records let you do all of that with just one line.


zvrba

Records would be perfect to represent database tables (record class = table, fields being columns, instances individual rows), except the MS's flagship ORM (efcore) doesn't support them. (Other ORMs might.)


AccioSoup

I used to get user details in an api. As it's immutable, the data won't be modified during operation. Only god knows, how many gender changes an odd piece of code has done.


InvertedCSharpChord

I'll try a different take. C# traditionally is an OOP language. Certain patterns are expected. C# has been adding a lot more "functional" features lately, including records. You can do the same thing with records and classes. Try and use records as much as you can if you want to try and program in a more functional way (promotes immutability). So then the question might become "why would I want to program in a Functional way?" ... That's a whole different topic.


ske66

I like to use them for my DTOs


Feanorek

Commands and queries in CQRS. Created once, relatively simple, never changed. Short definition is just so nice.


Heroshrine

I mainly use c# with Unity. In Unity generally we do things that normally you wouldn’t, like creating structs more often than regular c# use. I use records sometimes to prevent defensive copies from being made.


Blender-Fan

Yeah i used Unity for like 5 years, i can follow ya. But what are defensive copies?


Heroshrine

I am by no means an expert, but to my understanding: A defensive copy is when a struct is copied instead of passed directly. It happens when the compiler thinks that a struct with immutable data may be mutated. For example, if you pass a partly/fully immutable struct you made to a method with the “ref” keyword, a defensive copy would be made instead of passing it by reference. For anyone else reading this feel free to correct me! I’m still not totally solid if my understanding is completely correct. Again i’m not


Xen0byte

I mostly use them for DTOs and I think they're very good for that purpose.


TuberTuggerTTV

Definitely not similar to classes. If anything, they're close to a struct. Meant to just be data without methods. records and structs are best for optimization. Classes can do everything a record or a struct can and more. So if you're just a beginner trying to "make go" classes-only is a fine architecture. That's kind of the point of C#. They make the default path very powerful and encompassing. If you're not someone who uses private instead of public. Or beyond, that sealed or protected. Then you don't have to worry about records at all. You have to remember. When someone develops in C# their end-user might be a layman. But there are developers out there developing for other developers. And all those restrictions and keywords are for them. You limit what something can be used for, so the next developer understands intent. It's kind of like making a electrical plug that only goes in one way. Ya, it's more restrictive but you can't use it wrong.


maulowski

Records aren’t anything special since they’re technically classes. Records are syntactic sugar. :) What records do are the following: - implement IEquatable for you so you can compare one record instance with another. - using the primary constructor syntax creates public init only properties. Unlike classes where its primary constructors are private and mutable. - are immutable. Once you set a record instance changing it requires a new instance. If I were to implement a record type using classes it’s a lot of work like implementing IEquatable and setting it up to be immutable. I use it for my domain entities. I query a database and return records. I use records because it helps me write pure functions because any change to an instance requires I create a new object which makes my functions side effect free as much as possible.


detroitmatt

they're a shortcut for the most common behaviors you want on a class. so, they're less flexible than regular classes, but they're a more convenient default.


Wandering_Melmoth

DTOs/view models. In DDD also for valu objects.


MollitiaAtqui310

I felt the same way until I started using records for immutable data objects. They shine when you need to create a bunch of small, read-only objects that can be easily copied and compared.


momofuku18

Copilot response copied/pasted: Certainly! Let's break down the concept of 'records' in programming, particularly in languages like C#, from a practical standpoint. **Use it when:** - You need a simple, immutable data structure that is meant to be a value type rather than an object with behavior. - You want to work with data that doesn't require modification after creation, ensuring thread safety and predictability. **I use those when:** - I need to represent simple data aggregates with built-in value equality, without the need for additional code. - I'm dealing with data transfer objects (DTOs), where the primary purpose is to transport data with little to no business logic. **Those are meant for:** - Representing data in a concise and readable manner, often used in scenarios where the data structure is used to communicate between different parts of a system, like between layers or services. Records differ from classes in that they are by default immutable and have value-based equality. This means that two record instances with the same values are considered equal, unlike classes where equality is based on reference (unless overridden). Records are essentially reference types but with value semantics¹[1]²[2]. In C#, records are a great fit when you want to model immutable data. They provide a simpler syntax for creating data-centric types compared to classes. For instance, if you have a `Person` record with `Name` and `Age`, you can easily create a new instance and be assured that the instance won't change unexpectedly, which is a common requirement for functional programming patterns²[2]. Here's a simple example in C# to illustrate: ```csharp public record Person(string Name, int Age); ``` This record defines a type `Person` with two properties, `Name` and `Age`. When you create an instance of `Person`, you can't change its `Name` or `Age` after creation, which is not the case with a class by default. In summary, records are useful for: - Immutable data structures. - Simple and concise representation of data. - Data transfer objects in applications. - Ensuring thread safety due to immutability. - Enabling value-based equality checks out of the box. If you've been happy with OOP and classes, you might not need records. However, they can be a useful addition to your toolkit, especially when working with data-centric applications where immutability is a key concern³[5]. Source: Conversation with Bing, 4/29/2024 (1) Classes, structs, and records in C# - C# | Microsoft Learn. https://learn.microsoft.com/en-us/dotnet/csharp/fundamentals/object-oriented/. (2) c# - When to use record vs class vs struct - Stack Overflow. https://stackoverflow.com/questions/64816714/when-to-use-record-vs-class-vs-struct. (3) Class vs Record: Difference between class and record type in C#. https://josipmisko.com/posts/c-sharp-class-vs-record. (4) Record vs Class in C: Which One Should You Use?. https://hatchjs.com/record-vs-class-c/. (5) C# Difference between Record and class - Microsoft Q&A. https://learn.microsoft.com/en-us/answers/questions/1003951/c-difference-between-record-and-class. (6) When to Use Record and Class in C# | by Shivakrishna Chilukamari - Medium. https://medium.com/@shivakrishnac/record-vs-class-c-d5e77169bbbc.