Const Vs ReadOnly

Tags: Blog

With so many new and exciting technologies we geeks tend to forget about some basic concepts we learned a while ago.  This is the case at least for me. When I was making the transition from Classic ASP to ASP .Net, I researched every discrepancy I found on the framework or languages. Fast forward 9 years later (wow it has been that long) I could not remember for the life of me, the differences between the const and readonly keywords.

I remembered that the difference was that that const is a compile time constant while readonly is a runtime constant. This still was not clearing things for me to I started to play around bit and reading some C# books I have laying around. Ok so what is the difference?

The main difference is when the value is assigned. Consider the code bellow. This come straingt from the editor. Notice that values for both DaysInWeek and MonthsInYear are assigned. Now looks at the code bellow that. This comes from reflector. You may not notice right way but DaysInWeek was replace with the value 7 in the first for loop. This is because DaysInWeek in declare as a const and there for the value was assigned at compile time.

 public const int DaysInWeek = 7;
 public static readonly int MonthsInYear = 12;

 static void Main(string[] args)
 {
     Console.Write("There are ");

     for (int i = 1; i <= DaysInWeek; i++)
         Console.Write(i.ToString() + " ");

     Console.Write(" days in a week  and ");

     for (int i = 1; i <= MonthsInYear; i++)
         Console.Write(i.ToString() + " ");

     Console.Write(" months in a year.");
     Console.Read();
}

From Reflector

private static void Main(string[] args)
{
    int i;
    Console.Write("There are ");
    for (i = 1; i <= 7; i++)
    {
        Console.Write(i.ToString() + " ");
    }
    Console.Write(" days in a week  and ");
    for (i = 1; i <= MonthsInYear; i++)
    {
        Console.Write(i.ToString() + " ");
    }
    Console.Write(" months in a year.");
    Console.Read();
} 

What this means is that const variable most be value times (primatives, enums structs etc). Another caveat is since the value on const is assigned at compile time, if the constant variable changes for whatever reason (DaysInWeek changes to mean work days) the code that uses the const variable must be recompile is the constant comes from a different assembly.

I change the code to get the constant variable from  another assembly. The code now looks like this:

 static void Main(string[] args)
 {           
       Console.Write("There are ");

       for (int i = 1; i <= AnotherAssembly.Test.DaysInWeek; i++)
           Console.Write(i.ToString() + " ");

       Console.Write(" days in a week  and ");

       for (int i = 1; i <= AnotherAssembly.Test.MonthsInYear; i++)
           Console.Write(i.ToString() + " ");

       Console.Write(" months in a year.");

       Console.Read();
 }

To no surprise, the IL code is pretty much identical. Here is the real issue. I then recompiled “AnotherAssembly” after changing the value to DaysInWeek and guess what, the old value was still used because it was assigned at compile time.

Moral of the story, if ever in doubt, use readonly. In fact, although a bit slower it is preferred to use readonly constants at all times.

Hope this helps,

Dani

3 Comments

  • said

    <p>Hi Dani,</p>
    <p>I believe if you are using a const from an outside of the class it still references the constants field and the compiler doesn't do a replace. I believe it only does that replace if it is with in the same class.</p>
    <p>You can test this by doing the same above with Math.Pi.</p>
    <p>The difference between a const and a readonly variable is very distinct. A readonly variable can be set with in the constructor of the class. And a static readonly variable can be set within the static constructor of the class. The const like you mentioned is set at compile time. </p>
    <p>The main difference is this, const can only use compiler native variables, strings, numbers, anything that you don't have to instantiate, in other words anything you don't need to use the &quot;new&quot; keyword on. However it is a common misconception by developers to assume that it can use any ValueType, or struct, because there are certain value types namely DateTime and Guid that require instantiation. </p>
    <p>That is where the readonly keyword comes in, it can accept any class or struct instantiated or not. And can even be made to look like a const by combining static and readonly together. But there is a cost to using statics which I talked about on my blog:</p>
    <p> <a target="_blank" href="http://www.coderjournal.com/2009/08/static-constructors-in-net-3-5-still-a-bad-thing/">www.coderjournal.com/.../static-construc</a> </p>
    <p>But I believe your recommendation to always use readonly is wrong, because consts are very valuable in the way they are treated by the compiler, as indicated in your example above. They get rid of the need for magic numbers in your code, and when the compiler compiles you code to IL it takes care of putting them all in line for you, so that you can have the native performance of having the values inline and keep you code clean and readable.</p>
    <p>This last part is all in my opinion, I would love to know what other people think.</p>

  • dani said

    <p>Nick,</p>
    <p>I think we are saying a lot of the same things. However, the down fall of using const is that the value is replace with the literal at compile time event is the const is coming from another assembly. This means that if the value changes all referring assemblies must be recompiled. </p>
    <p>Readonly is a bit slower for various reasons. Now if I had to pick from potentially having the wrong value or being a bit slower I will choose the latter every time. </p>
    <p>Yes, there are some differences in the construction capabilities but I am not putting much weight to that.</p>

  • said

    <p>Just confirmed that I was wrong, and you were right about having them replaced. For some reason I thought they only where replaced internally. </p>
    <p>While I do agree with you for the most part, I still think like the unsafe, checked, and other lesser used keywords in C# that const has it's place if used correctly. </p>
    <p>But if you don't know when to use it or the consequences of using it, then you should use static readonly as a valid replacement for const. So I totally agree with you on that part.</p>

Add a Comment