Immutability in C# 5?
On the latest episode of .NET Rocks, Carl and Richard spoke to Anders about the new release of .NET and C# and what the future might hold. Predictably, Anders revealed that parallelism will be a focus on C# 5, with language enhancements to make use of things like Parallel Linq.
One of the things he spoke about was how difficult it is today to make a truly immutable reference type, with compile checking etc. This got me thinking about how immutability might work in a hypothetical future version of C#, without adding new keywords or language constructs. Immediately the “readonly” keyword sprang to mind.
The readonly keyword is applied to fields in a class. Fields declared as readonly can only be initialized inline or in the type’s constructor. Once they’re initialized, they are, as the name implies, read only.
public class Foo { public Foo() { Bar = 5; // Bar can now only be read } public readonly int Bar; }
Imagine if you could declare a class as readonly. All of the class’ fields would have to be declared as readonly too (a bit like the way static classes can only have static members), and its properties would have to have getters only – no setters. Any fields or properties would also have to be either a value type or a similarly read-only reference type, so there was no cheating by changing the property of a property. Let’s mock up a class to see what it might look like:
public readonly class Foo { public Foo(int bar, string buzz) { Bar = bar; _buzz = buzz; } // this would be fine public readonly int Bar; // no setter on our property, so that's fine too private readonly string _buzz; public string Buzz { get { return Buzz; } } // Fizz is a readonly class so this is also fine public readonly Fizz Fizz; }
This class would be guaranteed, at compile time, to be immutable. It would be safe to pass around between threads since nobody could change its state. It’d be fine to add methods to it which perform calculations based on the class’ fields and properties, since even they wouldn’t be able to modify the values (they’re all read only too).
I suppose the next step in this evolution would be a way to constrain methods or generic classes to only accept readonly types as their parameters, so that multithreaded code could be guaranteed not to change state. A simple “where T : readonly” generic constraint might suffice.
In theory it might be possible to take an existing “non-readonly” class and wrap it dynamically into a read only “proxy” (similar to a mock), but that would be complicated since any reference-type properties would need to be wrapped in a similar way, to prevent users changing their values. Not only that, but any collection property on the class would have to be converted to a ReadOnlyCollection or IEnumerable to prevent it from being modifies. It’d be a pretty hardcore piece of code.
I think a way to create a compile-time guaranteed immutable class in C# would be very helpful for people writing massively parallel code. This could be one way to do it … maybe the gurus like Anders have something entirely different in mind. Time will tell!
Comments
# zproxy
16/04/2010 7:41 PM
This is exactly how anonymous types work.
# mabster
16/04/2010 7:44 PM
I guess you're right, zproxy - anonymous types are, by design, immutable. Seems like the infrastructure is *almost* there already.
# Mike Minutillo
19/04/2010 10:06 PM
Awesome idea but is it really necessary to mark every field as readonly as well? This is a major beef I have with static classes. It's ceremony that the compiler could take care of for me. Also, can we have virtual classes where all members are virtual please?
# mabster
19/04/2010 10:09 PM
I totally see your point, Mike. I went with the "readonly keyword on each field" to match the existing "ceremony" with static members.
I do think there's an argument to be made that the explicit "readonly" (or even "static" or "virtual") keyword is handy when browsing a large class. Don't have to refer back to the class declaration to know what effect it has had on the current member.
Thanks for your comment!
# Jim Burger
23/04/2010 12:47 PM
Maybe take it a step further? http://pastie.org/930878 Still, I wonder if the issue will be detecting side effects from these getters at compile time. ATM the System.Diagnostics.Contracts stuff uses the [Pure] attribute, Maybe a pure keyword is next?
# mabster
23/04/2010 12:56 PM
I think you have good intentions, Jim, but the idea of the compiler automatically defining properties based on the ctor arguments does scare me a little bit! :)
Side-effect-free ("pure") getters and methods is the clincher, although at least we'd know that the class can't modify itself inside those getters - even its private fields would be read-only.
# Alberto
7/06/2010 3:50 AM
Your implementantion of a immutable type isn't enought. If you have a property that gets a non immutable reference type, then another class can mute the object state throught the reference to the non immutable object returned by the property.
# mabster
7/06/2010 8:36 AM
Alberto,
I think I've covered that. I specifically said that in this implementation, a readonly class would only be allowed to have properties who are value types or other readonly reference types.
# Alberto
8/06/2010 2:54 AM
I did not read this part. I think that your idea is a natural one according to the language. If we omit the readonly-value type condition on properties. Then the compiler can check for us if we made some kind of state change if possible or the runtime if not. And could be natural in such case don't to use de readonly modifier in the rest of the class.
# WCWedin
4/08/2010 1:19 AM
Obviously, const members should also be allowed, so there might be a loss of clarity if you try to remove the readonly keyword from each field. Just a little, though.
Also, I don't think the return value of a reference-type, read-only property would need to also be a readonly class. As long as you restrict fields to other readonly classes, you could only return a new instance of that class. In that case, different threads will be working with different instances, so you can guarantee that, as you said, "at least ... the class can't modify itself."
That said, you can't guarantee that different instances of a given class are thread-safe. Static members could really ruin your day here.
On the other hand, it just seems a shame to impose a restriction that would force you to thread the entire hierarchy with the readonly keyword. You might as well just make everything a struct.
I don't think any sort of wrapping would work in this case, by the way. Instance fields and properties can probably be transformed in a general way if you're very meticulous, but once the spectre of shared state starts haunting your classes, it's damn near impossible to shoo it off.
# Tar
2/02/2011 7:22 PM
A class is immutable when all it's fields are immutable from the "public" point of view.
It has nothing to do with actual types of fields or properties - having a property of non-immutable type, encapsulating a field of the same type, the important part is whether it returns the value of the field, or a copy.
In other words, the proposed "readonly class" specification is too restrictive
# mabster
2/02/2011 8:01 PM
I dunno if I agree with that, Tar. Immutable classes should never change IMHO, even if the change happens from an internal trigger. I'd be keen to hear others' opinions on that one.
# Colin Scott
2/02/2011 9:03 PM
If a class is immutable then I can pass it anywhere without worrying about how it is used. I can pass it to code I do not control, or that has not been written yet and have confidence my code will not break because the instance has been mutated unexpectedly. I can also pass the instance between threads as it will be inherently threadsafe.
If the class is merely faking immutability this does not hold. Bugs caused by this deception are likely to be expensive to fix and sufficiently obscure that they're not found until production. Lying about immutability gains nothing and can be actively hazardous. Updating state internally is all very well until someone uses your class in multiple threads when you never expected them too.
(I'm aware an immutable class can contain dangerous methods, let's assume a properly written class does not)
# Aivar
13/03/2011 6:56 AM
Immutability is trickier than it seems. John Boyland has nice paper about it (yes, he talks about Java, but C# and Java are about as similar as languages can be).
www.jot.fm/.../article1.html
# Eugene
18/04/2011 8:26 PM
c++ have const/mutable modifiers for class functions/fields.
And I think it will be great to introduce it into C#.
Const greatly impruve code-safety.
# Gabriele Giuseppini
11/05/2012 9:26 PM
It'd be awesome to have readonly classes in C#. I agree with Eugene, I was a big fan of const when I used to code C++.
Ideally, I'd like to have the possibility to declare a parameter as "readonly" with the same semantics as the C++ "const".