Skip to Content
All posts

Mastering Immutability in C#

A Deep Dive for Software Engineers

3 min read ·  — #csharp-interview#middle-specialist#immutability

Mastering Immutability in C#

Introduction

Greetings seasoned C# developers! If you're reading this, chances are you're not here to learn the basics. You're here because you understand that the devil is in the details. Mastering those details is what distinguishes a competent programmer from a remarkable one. One such devilish detail is "Immutability," a concept that might seem straightforward at first glance but offers a multitude of subtle advantages—and complexities—when implemented correctly.

Immutability has been a cornerstone concept in functional programming and has recently found its way into the heart of object-oriented languages like C#. With the advent of features like records and property initializers (init), C# has bolstered its support for immutability, making it easier than ever to create robust, maintainable, and thread-safe applications.

So, let's put on our architect hats and take a deep dive into the ocean of immutability in C#, exploring records, property initializers, and other features that empower you to write cleaner, safer, and more efficient code.

Records: Immutable by Default

What Are Records?

In C# 9.0 and later, record types are a way to create immutable reference types with value semantics. In simpler terms, once a record object is created, it can't be altered. Records are ideal for modeling immutable data or "data carriers" where you don't want the state to change once instantiated.

Syntax

Here's a quick example:

record Person(string Name, int Age);

This one-liner creates a record with a constructor, properties, and built-in methods for equality checks and cloning.

Real-world Scenario

Imagine you are developing a high-concurrent system for a financial trading platform. Each trade object, once created, should not be modified to ensure the integrity of the transaction.

record Trade(string Ticker, double Price, int Quantity);

With & with Expression

You can create a new object that is a copy of an existing one with only specific properties modified using with:

var trade1 = new Trade("AAPL", 150.25, 100);
var trade2 = trade1 with { Price = 160.50 };

Property Initialization with init

What Is init?

In C# 9.0, you can use the init keyword in properties to make them writable only during object initialization. It ensures that after the property is set, it cannot be changed again, thereby making the object immutable post-construction.

Syntax

public class MyClass
{
    public string MyProperty { get; init; }
}

Real-world Scenario

You are building a system for academic transcripts. Once a grade is assigned, it should not be changed.

public class Grade
{
    public string Subject { get; init; }
    public double Score { get; init; }
}

Composition with Records

You can also use init in records to add more complex logic during initialization.

record Student(string Name, int Age)
{
    public List<Grade> Grades { get; init; }

    public Student
    {
        Grades = new List<Grade>();
    }
}

Why Is Immutability Crucial?

Thread Safety

Immutable objects are inherently thread-safe as there is no way for one thread to alter the object's state that could affect other threads.

Predictability and Maintainability

Immutable objects make the codebase easier to reason about, debug, and maintain since state changes are minimized.

Functional Programming Patterns

Immutability is key to functional programming concepts like pure functions, which lead to more maintainable and testable code.

Conclusion

For engineers, understanding and employing immutability effectively is like adding an extra layer of polish to your craftsmanship. With record and init features, C# provides modern tools to implement immutability with less boilerplate and greater expressiveness, so you can focus on solving the actual business problems. So the next time you're designing a system, ask yourself, "Can this be immutable?" Chances are, you'll find a compelling reason to say yes.

References