Many a times people have asked me the difference between a readonly variable and a constant. With this article I hope to clarify that. I would also delve on when to use readonly and when to use constant variables.
readonly variables are also know as runtime constants. One can initialize the value of readonly variable to any type. One can have one’ own custom object as a readonly variable. Once initialized the readonly variables cannot be tinkered with other than in the constructor. If one really wants to change the value then that can only be done in the constructor. E.g. is shown below.
Also when you compile your code the readonly variable will have a reference to the actual object. readonly variable are slightly slower than constants in performance. readonly variables can be static.
The above e.g. shows the readonly variable as static and the value is decided at runtime. readonly variables cannot be initialized inside a method. As readonly variables can be assigned in the constructor each instance of a class can have its own instance of the readonly object.Const variables
const variables are compile time constants. By compile time constants it means the actual value is replaced and saved in the IL (Intermediate Language). For this reason one can only use primitive types as const variables. Enum and strings can also be used as const variables. Primitive types, enum and string are the only datatypes which can be replaced with literal values. DateTime variable cannot be used as a const variable. Though it is of value type it cannot be used as a const variable. The reason is that compile time constants cannot be initialized using the new keyword. const variables are static by default. Few e.g. of const variables are pasted below.
In the above e.g. we have primitive types along with string and enum type as well. We have also declared a const variable inside a function as well. If you use readonly in a method scope you will get the following error.
The modifier 'readonly' is not valid for this item
One thing to note is that readonly keyword will not be available in the intellisense of a VS inside a method. Just to highlight the difference I have pasted two classes below and their respective IL code.
The above classes highlights the different uses of a readonly variable. We are using int, double, string and user defined type. Also highlighted is the manipulation of a readonly string variable inside a constructor. Below IL code.
If you see the above IL you will notice against all the value we have defined there are some instruction like “ldc.i4.s”, “ldc.r8” and “ldstr”. Each instruction has its own meaning. ldc.i4.s means push a number value onto the stack as an integer, ldc.r8 implies that push a float onto the stack and ldstr is an instruction to push a string object. If you further go down and take a peek into the print function you can see few IL instructions which are basically instruction to push and pop data to stack and finally replace the reference value from the stack.
Now let’ see the code where a class has const variables.
The above class is similar to the one we have already seen above except for a public const string variable added. The IL generated for the above code is pasted below.
If you notice the IL code above all the const variables have been replaced by the actual values. At the bottom you can see the variables hold the actual value rather than only declaration as in the case with readonly variables. If you analyze the method (SomeMethod) in the IL you will notice that instead of some instruction to use the value by reference the actual values are used. In the case of readonly variable there were instruction to use the values by reference. But with const variables the actual values are being used.
With above IL code it is clear how readonly and const variables behave.
When to use readonly/const variables?
From the above most of you may be clear when to use const and when to use readonly variables. const variables can be used when the value of the variable is rarely going to change like the value of PI. Readonly can be used when you want to use the variables by reference or you want to inject runtime values. Also const variables are faster than readonly. By faster I don’t mean they are lighting fast. They give small performance benefit over readonly variables. Here one should use due diligence as const variables don’t provide any flexibility. Once assigned const variables cannot be changed.
A real time problem we faced in one of our projects. In one of our projects we had defined const and readonly variables in a separate project and added a reference of it in another project. After the release of the project we got requests from client to change few things. As a result we had to make changes in the const variables. Since the changes were only in few places, our team decided to just distribute the changed project and not to reinstall the whole application. So as a patch release we included few dlls in the installer and installed the same at the client place. But behold, the changes were not showing. The reason, the const variables used in other parts of the applications were not updated as only few projects were compiled and not the whole of the application. Because of this const values which were replaced were not updated. Confused? Let’ see this with an example. Below is a sample code which has a const and readonly variable in a separate project.
The above code is pretty straight forward. In a namespace called SeparateProject, we have a class called Values. Values class has one const variable called PI. Another readonly variable called “Value1” having 40000 as the value. The above project is referenced and used in the below project. The code is pasted below.
The above code is pretty straight forward. It is a console app which prints “3.14” and “40000” respectively. Now let’ change the values inside Values class and compile only that project.
What we have done here is changed both the variable’ values and compiled only the “SeparateProject” project. Also we have replaced the dlls in the debug folder of the bin directory of “ReadOnlyConst” project with the latest compiled dll of “SeparateProject” project. If you run the console app, you will see the value of PI printed as “3.14” whereas the value of “Value1” printed as “80000”. You can see the value of PI has not been updated but the value of “Value1” has been updated. The reason is where ever const variables are used the values have been replaced where as in the case of readonly there is reference to the actual variable. In other words, in the main function the value of PI has been replaced by the actual value and that of “Value1” has reference. As we have not compiled this part of the application the substitution has not happened. Just to shed more light lets see the IL for the console app.
The above pasted IL is that of the main method of the console app. At line no 7, you can see the value of PI. Whereas at line no 12 instead of any value we have some IL instructions. Since we have not compiled the console application the altered values have not been updated.