C# readonly vs Java final
There is a technical reason for the behavior of readonly
: in the created assembly's metadata the field is marked with the initonly
attribute that will ensure the field is not modified outside a constructor.1 However, while unverifiable, by taking the address of the readonly field it is still possible to change its value. Verifiable IL and C# will not allow you to do this.
At compile time it is impossible to enforce this for all methods, since the compiler would have to analyze all possible orders in which methods could be called. At runtime it would probably be a burden on the CLR and negative for performance if it had to check every field write whether it has been written to before. Instead, it is safer that C# and the CLR just don't allow the field to be assigned a value anywhere except in the carefully analyzed scope of a constructor.
In my opinion this does not make the readonly
keyword any less valuable. I use it all over the place for fields whose value is provided only by the constructor (e.g. creating a list, or storing a constructor argument). C# will ensure that I won't change the field after that ever again, ensuring that I cannot accidentally set it to null
or anything.
1) Thanks to Eric Lippert for pointing this out.
MgSam
I am a full time software developer that works primarily with C#/.NET, TypeScript/JavaScript, HTML/CSS, XAML, and T-SQL.
Updated on June 04, 2022Comments
-
MgSam almost 2 years
In Java,
final
means a variable can only be assigned to once, but that assignment can happen anywhere in the program. In C#,readonly
means a field can only be assigned in a constructor, which, IMO, is significantly less useful.As we all know, C# was heavily influenced by Java design, but this difference has always puzzled me as being very odd. Does anyone know if there's a technical reason in the CLR that resulted in the less-useful behavior of C#'s
readonly
vs Java'sfinal
?EDIT:
In response to the comments; I'd like to point out that I am well aware of the benefits of immutability, and I use it all over the place. I believe
readonly
is less useful than Java because of this:public class Foo { private readonly int _bar; Foo() { _bar = 5; } }
Whoops, I actually need to initialize that value in a helper method!
public class Foo { private readonly int _bar; Foo() { initialize() } private void initialize() { _bar = 5; //Can't compile because of semantics of readonly } }
-
MgSam about 11 years@Virtlink Thank you for your answer. It's nice that not everyone just looks for excuses to close things.
-
ssss over 10 yearsThe first paragraph is wrong. You can modify a readonly field via Reflection, using only safe C# and verifiable IL. You can even change the value of
string.Empty
that way. Perhaps you meant trusted code, which is a completely different concept from verifiable IL. Untrusted code cannot use (most of) Reflection, but verifiable IL can. -
Daniel A.A. Pelsmaeker over 10 years@Timwi You are correct, but when you bring reflection into the picture, all bets are off. I didn't mention it as it is not relevant to the question. That makes my first paragraph not wrong, at most incomplete.
-
Caffé about 9 yearsThe curious thing is that Java final and C# readonly, for the sake of this question, work exactly in the same way: you cannot assign value to them anywhere in the class but only in the constructor or in its declaration
-
Daniel A.A. Pelsmaeker about 9 years@Caffé: That's only true for C#. In Java you can assign the value anywhere, but only once. You'd usually want to do that in the constructor for sanity's sake, but that's not required. You will get an exception if you try to assign it a second time, no matter where you do that.
-
Caffé about 9 years@Virtlink What java compiler have you been using? Check out the question's second example not working in Java: ideone.com/iq1EbV.
-
granadaCoder over 5 years"only by the constructor" is great for constructor based dependency injection.