Monday, September 22, 2008

Const OR Static ReadOnly


When declaring a member which will hold a constant value, I have seen instances there are folks who use ‘const’ and also there are folks who loves to use ‘static readonly’. There are debates over it, which one is the correct way to follow … looking down inside(MSIL level ), here is what I found.
Let us consider, we are writing a Library and we have declared two variables in a public class as mentioned below …
public static readonly int ReadOnlyStatic = 100;
public const int ReadOnlyConst = 100;

Now let us create a Console Application which will have a reference of the above library, and in the Main method we write the following code block…
static void Main(string[] args)
{
int _staticReadonly = TestClass.ReadOnlyStatic;
int _const = TestClass.ReadOnlyConst;
Console.WriteLine("Constant:{0}, ReadOnlyStatic:{1}", _const, _staticReadonly);
If we do ILDASM of the codeblock, here is what we will found ….
.locals init ([0] int32 _staticReadonly,[1] int32 _const)
IL_0001: ldsfld int32 [POC_ConstantVsReadOnly]POC_ConstantVsReadOnly.TestClass::ReadOnlyStatic
IL_0006: stloc.0
IL_0007: ldc.i4.s 100
IL_0009: stloc.1
So, it’s clear from the MSIL that in case of const, the compiler assign(hardcode) the value into the variable( refer to the second underlined statement), and in case of static readonly it refers to the class member(refer to the first underlined statement).

What does that mean ? That means for some reason if we change the value of constant in the Library we have to recompile all the assemblies which have a reference to this library, however if we change the value of static readonly and then we would be fine if we just replace the compiled library in the referenced assemblies Bin folder.
To test this feature, let us do this:
A. Let us change the value in the Library as mentioned below and then compile the library.
public static readonly int ReadOnlyStatic = 50;
public const int ReadOnlyConst = 50;

B. Now manually replace the newly complied library in the console app Bin folder( I had set ‘copy local’ as true while having a reference of the library ) , let us run the console application( without compiling), now we will see the value of ‘const’ is 100 but the value of ‘static readonly’ as 50, now compile the Console app project, and this time both of the will show the value as 50.

So, we must remember if we declare a member as ‘const’ in a library, then upon changing the value all the dependent applications have a to release a new version just because the constant value has been changed.

What about performance ? Only on the first call, static readonly will be slower compare to const, the subsequent calls should be as good as const.

5 comments:

Anonymous said...

First of all we should not compare 'const' with 'static readonly'; otherwise it will be comparing apple with orange. 'const' should be used for constants which do not depend on contexts (universal constants) whereas 'static readonly' should be used for constants which do depend on contexts (context based or limited constants). For 'const', value will be set during compilation time itself; whereas for 'static readonly', value will be set during initialization at runtime.

For example, number of days in a week should be 'const' where as number of standard working days in a week is 'static readonly' – usually it will be 5, but in some countries (France?) it will be 4 or could be something else in future.

"Only on the first call, static readonly will be slower compare to const, the subsequent calls should be as good as const.” – I do not agree with this. Since value of a 'const' is known at compilation time, compiler can do lot of optimization based on that value. Moreover if there is a complex math function f(x) and x is a 'const', then compiler can compute that function at compilation time; but that is not possible for 'static readonly'. So, in my opinion, 'const' will definitely give better performance, but that may not be significant in some cases.

Finally, to avoid recompilation of dependable assemblies, we should not use 'static readonly' in place of 'const'; instead we could declare our 'const' as 'internal' (so we can still have benefits of 'const') and expose that 'const' through a public static method.

Neo said...

Pal b,
here goes my cents ...
Agree with ur defination of const and read only.

[Pal b]
'const' will definitely give better performance, but that may not be significant in some cases.

[Neo]Agree, it gives slightly better performance but in most of the cases negligable.

[Pal b]
Moreover if there is a complex math function f(x) and x is a 'const', then compiler can compute that function at compilation time; but that is not possible for 'static readonly'.

[Neo] Right, in cae of CONST, C# compiler will optimize the code, and in the case of STATIC READONLY ,JIT should optimize the code.

[Pal b]
to avoid recompilation of dependable assemblies, we should not use 'static readonly' in place of 'const'; instead we could declare our 'const' as 'internal' (so we can still have benefits of 'const') and expose that 'const' through a public static method.

[Neo]
Nice idea, however you are loosing C# compiler optimization, should be same as Static ReadOnly...

Anonymous said...

Few points –

First – 'const' can give you much better performance due to compile-time optimization, pre-computation, no chance of page-fault, less memory lookup etc – I guess it’s more than *slightly*.

Second - JIT compiler will not be able to optimize for 'static readonly' as JIT compilation may happen before initialization of 'static readonly'. I doubt even it ever tries to do that level of optimization.

Third – 'internal const' is as preferment as 'public const' for an assembly; not sure why do you think we will miss compiler optimization. Dependent assemblies will miss the benefits of 'const' though. But with 'static const' we will miss the benefits of 'const' in main assembly itself.

Finally, need of recompilation of dependant assemblies cannot be the reason for converting a 'const' to 'static readonly' … changing the value of a 'const' is nothing but like changing some function-signatures and assembly versioning is there handle such scenario.

Unknown said...

hey neo,
may i have your contact id? mine is kulkarnisushant@gmail.com

Anonymous said...

Many a true word is spoken in jest.