Why Are Mutable Value Types Even Possible?

4 commentsWritten on May 17th, 2009 by
Categories: Software Development

A coworker of mine was recently trying to figure out why some code wouldn't compile.

Consider the following code:

            var point = new System.Windows.Point(5, 7);
            point.X = 6;
            point.Y = 8;
            Assert.AreEqual(6, point.X);
            Assert.AreEqual(8, point.Y);

This compiles and works. Now consider the following class:

    public class SomeClass
    {
        public System.Windows.Point SomePoint { get; set; }
    }

And then this small piece of code:

            var myObject = new SomeClass
            {
                SomePoint = new Point(2, 3)
            };
 
            myObject.SomePoint.X = 5;

You'd typically expect that this code would compile, right? Well it doesn't. It fails with the following compiler error:

error CS1612: Cannot modify the return value of 'SomeApp.SomeClass.SomePoint' because it is not a variable

Not exactly what you would expect, right? Well, the compiler error in this case is actually a good thing, though the message isn't as clear as it should be. See, System.Windows.Point is actually a value type instead of a reference type, and as you should know, value types behave very differently from reference types when passed around. You basically get a copy every time instead of the actual instance.

Let me just borrow the explanation of the "DO NOT define mutable value types" guideline, from Microsoft's Framework Design Guidelines:

Mutable value types have several problems. For example, when a property getter returns a value type, the caller receives a copy. Because the copy is created implicitly, developers might not be aware that they are mutating the copy, and not the original value.

Now the compiler error makes sense, right? Well, the message still sucks, but it makes sense that the compiler would protect you from making this mistake.

It won't protect you from the following mistake though:

            var myObject = new SomeClass
            {
                SomePoint = new Point(2, 3)
            };
 
            var point = myObject.SomePoint;
            point.X = 5;

This code will compile, though if you expect that myObject.SomePoint.X will return 5, you're in for a treat. Hopefully nobody writes code like this, but imagine having to debug something like this in some legacy code that was never properly tested.

But really, why are mutable value types even possible? In what situation does a mutable value type make sense? I'd really like to know, so please point out those situations in the comments if you know of one. The only reason i can think of is performance but the number of situations where a mutable value type is going to give you a significant performance boost is probably so small that it would've made more sense to enable mutability for value types with a language keyword or something like that. Unless there is another benefit that i'm not aware of yet?

  • http://msmvps.com/blogs/senthil Senthil Kumar

    My guess is to make initialization less painful, if the type has a bunch of fields. Although having a large number of fields in a struct is not recommeneded.

    That apart, try changing SomePoint to a public field (rather than a property), and the code will compile and work as expected. I’ve always found that a bit weird.

  • http://davybrion.com Davy Brion

    @Senthil

    well, in that case it’s not really so weird because then you have direct access to it, instead of it being passed around as so happens when using a property.

    but the fact that the code itself would work when using a field makes the whole thing even more likely to cause confusion

  • Pingback: Reflective Perspective - Chris Alcock » The Morning Brew #349

  • http://incrediblejourneysintotheknown.blogspot.com/ Daniel Earwicker

    Structs seemed like such an irresistable addition (compared to Java) when I first read about them, but they are practically useless. The only places you might need them is in order to create an array of structs for some obscure interop scenarios, or as an optimisation technique (but ONLY after profiling reveals abnormally high pressure on the GC).

    In terms of general program design, forget about them. They’re just one problem after another.

    If they are needed for those edge-cases, fine, but maybe they should have only worked inside an “unsafe” block! They should have been made as unattractive as possible, to deter people from using them where a class would be fine.

    For example, it should have been illegal to define events in a struct. Events signal a state change, and structs ought to be immutable, hence an event on a struct should ring alarm bells.

    Also the inability to control how and when they are constructed makes large-scale design very difficult. Any struct can always be constructed with its contents zero-inited, and there’s no way to ban that.