I have been reading this question and a few other answers and whilst I get the difference between changing the reference and changing the state of the current instance I'm not certain why this means that I shouldn't mark it readonly. Is this because marking something as readonly tells the compiler something special about the instance and so it is able to then treat it as thread safe when it actually might not be?
Presumably there are situations where I don't want the instance to be able to be changed, but don't mind if the state of the instance is changed (singleton maybe. /me prepares for flames) What are the consequences for marking the instance readonly if I want this?
There are no (runtime/environment-based) consequences. The compiler won't freak out, your runtime won't explode, and everything will generally be fine.
It's only FxCop (a static analysis tool that some people use) that has a warning about this. The reasons for the warning are explained in the thread you've linked to (semantically, it may not be clear that the object isn't actually "readonly", only that the variable can't be "reassigned").
Personally, I disagree with the rule, so I'd just disable it (if you're running FxCop and it is concerning you).
An interesting related point: mutable readonly structs are a bad idea because of situations like this one:
http://ericlippert.com/2008/05/14/mutating-readonly-structs/
Most of the people to whom I've shown this code are unable to correctly predict its output.
Mutable readonly structs have the problem that people think they're mutating them but really they are mutating a copy.
Mutable readonly ref types have the opposite problem. People think they're deeply immutable but in fact they are only shallowly immutable.
I think the point is that it could be misleading - an unwary reader might assume that a readonly variable was effectively a constant, which it wouldn't be.
I would treat it as a suggestion more than a rule - there are certainly cases where it could be reasonable, but should be used with care. (In particular, I'd be nervous if the mutable state were exposed to the outside world.)
These two type declarations are both valid and useful, although they mean different things:
If you really want a constant reference to a mutable object it seems objectionable to be forced to make do with a mutable reference for any reason, let alone a bad one. In multi-threaded programming the constant reference could save you having to synchronize on the owning object (you still have to synchronize on the mutable object via the reference, but that's a finer-grained lock).
Unwary readers are probably unwary writers too - can't do much about them short of:
const SourceRepository cvs = new ReadOnlyRepository(...);
C++ has a means of enforcing a constant pointer to a constant object (references are a bit different in C++):
Object const* const constantPointerToConstantObject = ...;
It's one of the few C++ features that I miss in C#/Java.
D has an even better keyword (immutable) that enforces transitive immutability. D's immutable does allow the compiler to make the kind of optimizations that you're worried about and guarantee safety. D also has const for non-transitive const-ness, which implies that both transitive and non-transitive forms are independently useful.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With