#780 – The Case for Immutable structs

You can run into problems when a struct is mutable.  (E.g. when used as a property, in a collection, or when modifying a struct through a method).

You can avoid problems by being careful about how you use the struct and by being aware of value type semantics (you get a copy of the value-typed object, rather than a reference to it).

You can also avoid problems by making your custom structs immutable.  This means:

  • Exposing the data in the struct exclusively through read-only properties
  • Defining methods that modify the value in the struct to return a new instance of the struct

For an example of this, look at the System.DateTime type, which is a struct.  Its properties all have only a get accessor, so you can’t change them.  And methods that change the value of a DateTime, e.g. AddDays, return a new instance of a DateTime.

Advertisements

#778 – A struct Isn’t Mutable When Used in a Collection

struct is normally mutable, i.e. you can modify the values of its members directly.

However, if a struct is used in a collection class, like a List<T>, you can’t modify its members.  Referencing the item by indexing into the collection returns a copy of the struct, which you can’t modify.  To change an item in the list, you need to create a new instance of the struct.

            List<DogCollarInfo> collarList = new List<DogCollarInfo>();

            // Create a few instances of struct and add to list
            collarList.Add(new DogCollarInfo(0.5, 14.0));
            collarList.Add(new DogCollarInfo(0.3, 12.0));

            // Compile-time error: Can't modify '...' because it's not a variable
            collarList[1].Length = 22.0;

            // Do this instead
            collarList[1] = new DogCollarInfo(collarList[1].Width, 22.0);

If you store the structs in an array, then you can change the value of one of the struct’s members.

            DogCollarInfo[] arr = new DogCollarInfo[2];
            arr[0] = new DogCollarInfo(0.5, 14.0);
            arr[0].Length = 5.0;  // OK

#777 – A struct Isn’t Mutable When Used as a Property

A struct is normally mutable, i.e. you can modify the values of its members directly.  Assume that we have a DogCollarInfo struct with Width and Length members.  We can create the struct and then later modify it.

            // Create struct
            DogCollarInfo collar1 = new DogCollarInfo(0.5, 14.0);
            collar1.Dump();

            // Modify data in struct
            collar1.Length = 20.0;
            collar1.Dump();

777-001

However, if a struct is used as a property in another object, we can’t modify its members.

            // Create Dog object and set Collar property
            Dog d = new Dog("Kirby");
            d.Collar = collar1;

            // Compile-time error: Can't modify Collar because it's not a variable
            d.Collar.Length = 10.0;

Because the struct is a value type, the property accessor (get) returns a copy of the struct.  It wouldn’t make sense to change the copy, so the compiler warns us.

You can instead create a new copy of the struct:

            // Do this instead
            d.Collar = new DogCollarInfo(d.Collar.Width, 10.0);
            Console.WriteLine("Dog's collar:");
            d.Collar.Dump();

777-002