I am eager to know the difference between a const variable and a static variable.
Is a const variable also always static? What is the difference between them?
const fields can only hold value types or System.String. They must be immutable and resolvable at compile-time.
static readonly fields can and generally do hold reference types, which (other than strings) can only be created at runtime. These can (but shouldn't) be mutable types; the only thing that cannot change is the reference itself.
If you need to maintain a "constant" set of instances that are reference types, you generally do it with a set of public static readonly fields, such as the members of System.Drawing.SystemColors.
Last but not least, initialization of a readonly field can be deferred until the execution of a constructor, which means that it even though it can only be written to once, it does not always have to be initialized with the exact same value. True constants declared with const can only ever have a single value (specified at compile time).
One subtle but crucial difference is that consts are evaluated at compile time, whereas statics are evaluated at run time. This has an important impact on versioning. For example, suppose you write:
public const int MaxValue = 100;
You compile and ship your assembly (Assembly A). Then someone else writes an assembly (Assembly B) which references MaxValue. In this case, the value 100 is compiled into their assembly as well as yours.
If you had written this:
public static readonly int MaxValue = 100;
then the reference in their assembly would remain just that, a reference. When someone ran Assembly B, the value 100 would be loaded from your assembly, Assembly A.
This can, for example, affect simple patching scenarios. If you issue an updated Assembly A where MaxValues is declared as 200, and the user copies that version over the previous version (but does not recompile Assembly B), then in the first scenario Assembly B will continue to operate as if MaxValues were 100, because that's the const value that was compiled into Assembly B. In the second scenario, Assembly B will pick up the new value because it loads the non-const static variable at runtime.
As you say, both static and const are attached to a type rather than an instance of a type. However, you can still change static items. You cannot change const items.
Be careful with this, though. If your const item is a reference type, the assigned expression has to be evaluated at compile time, and that means that the only possible value you can give the reference is null (with the notable and useful exception of strings).
A (non-readonly) static can be changed after it has been declared whereas a constant cannot. In addition, a constant cannot be set using a function whereas a static variable can.
A constant is a variable that cannot be changed in value.
A static is a variable that cannot be used outside the scope of it's declaration. That is, if it is a global variable then it can only by used in the file that declares it. If it is a variable inside a function, then it can be use only inside that function.
Related
This question already has an answer here:
Memory allocation for const in C#
(1 answer)
Closed 8 years ago.
The title of the question is self explanatory. I wonder if a member that is declared const is singleton for all instances of the class or each instance has it's own copy.
I've read some questions about const but most of them refer to const variables inside a method.
C# constants are implemented as fields with the literal constraint in the Common Language Instructructure. Looking up ECMA-335 §I.8.6.1.2 provides the definitive answer (emphasis mine):
The literal constraint promises that the value of the location is
actually a fixed value of a built-in type. The value is specified as
part of the constraint. Compilers are required to replace all
references to the location with its value, and the [Virtual Execution System] therefore need
not allocate space for the location. This constraint, while logically
applicable to any location, shall only be placed on static fields of
compound types. Fields that are so marked are not permitted to be
referenced from CIL (they shall be in-lined to their constant value at
compile time), but are available using reflection and tools that
directly deal with the metadata.
So there you go, the values of const fields must be copied by compilers directly into the instruction stream (typically using ldc.* instructions). They do not exist in a referencable location, but need to be available in the metadata and via reflection. They could be implemented like static fields, but do not have to.
Constants are usually something that can be evaluated compile time and compiler is likely to replace it with the evaluated value.
Also Const means static (see link below)
A constant expression is an expression that can be fully evaluated at
compile time. Therefore, the only possible values for constants of
reference types are string and null.
Source:
C# static and const variables memory
Memory allocation for const in C#
C# do const fields use less memory?
const implies static so there is only one instance per class.
Edit: Add Reference
Constants are resolved at compile time, and the actual value of the constant is stored in the compiled DLL in place of references to the constant.
In addition, the constant is saved as a member of the class in the DLL. This allows public constants to be referenced by external DLLs. However, the external references are also converted into the constant value when they are compiled.
A ramification of the compile properties of constants means that if DLL1 refers to a constant in an external DLL2, and the constant definition in DLL2 changes, then DLL1 will not have the updated value unless it is recompiled, too.
If you want to work around this problem, you're better off with public properties returning the constant. See the answer to this question for more information.
I confirmed the above behavior with .NET Reflector.
I believe that value itself is in-lined anywhere it's referenced at compile time. Meaning, if I have const int x = 10; and then I use x 100 times throughout my source, each of those 100 references to x will actually just be replaced by 10 prior to the actual compilation.
Const is meta-data...
It is not in memory, but using the const - telling the compiler "you see the literal under the name of that const... put it here" (literal is a number, or string, or null, in the middle of the code, like in for (int i = 0... that 0 is literal).
Now, in most cases - these (literals.. from now on - we're talking about literals) are value types... what singleton has to do with value types?! Nothing... The data of a value type is copied from one location to another. so it cannot be a singleton.
What about nulls? null is a possible value of a reference, which signals "I'm referencing nothing" - So again.. Singleton is irrelevant here (For nullable value types - null is just like the default constructor... And they're value types... So this is like case 1).
And what about string literals?! (eg: "hello world" in the middle of the code)
This is a special case.
Every string literal is cached inside an intern table... So - every time you use the same string-literal - you're actually referencing the same object in memory.
But is doesn't mean that every string with the same value is the same object:
string ab = "ab";
string anotherAB = "ab";
string another = 'a'.ToString() + 'b'.ToString();
Console.WriteLine(object.ReferenceEquals(ab, anotherAB)); // true
Console.WriteLine(object.ReferenceEquals(ab, "ab")); // true
Console.WriteLine(object.ReferenceEquals(ab, another)); // false
Console.WriteLine(object.ReferenceEquals("ab", another)); // false
I am trying to declare a PI constant like this:
public static const double PI = Math.PI;
but why am I getting this error?
The constant 'Calendar.NewCalendar.PI' cannot be marked static
const implies static (you don't need an instance to reference the const value).
I want to also add this important point: When you link against (reference) an assembly with a public const, that value is copied into your assembly. So if the const value in the referenced assembly changes, your assembly will still have the originally compiled-in value.
If this behavior is not acceptable, then you should consider making the field a public static readonly field.
Lib.dll, provided as binary:
public class Foo {
public const int HATS = 42;
public static readonly int GLOVES = 33;
}
App.exe, references Lib.dll:
Foo.HATS // This will always be 42 even if the value in Lib.dll changes,
// unless App.exe is recompiled.
Foo.GLOVES // This will always be the same as Foo.GLOVES in Lib.dll
From MSDN:
Don’t create a constant to represent information that you expect to change at any time. For example, don’t use a constant field to store the price of a service, a product version number, or the brand name of a company. These values can change over time, and because compilers propagate constants, other code compiled with your libraries will have to be recompiled to see the changes.
From DotNetPerls:
DLLs. When you use a const field or declaration, the C# compiler actually embeds the const variable's value directly in the IL code. Therefore, it essentially erases the const as a separate entity.
Caution:
If programs that depend on a const are not recompiled after the const value changes, they may break [because they'll continue to use the previous value].
A constant is static by definition.
You can't have static const. Try readonly instead of const or simply drop the "static" since "const" is implied static anyway.
Constants cannot be replaced in the code during compilation, not runtime, so there's no requirement for static vs instance definitions.
All constants declarations are implicitly static, and the C# specification states that the (redundant) inclusion of the static modifier is prohibited. I believe this is to avoid the confusion which could occur if a reader were to see two constants, one declared static and one not – they could easily assume that the difference in specification implied a difference in semantics. Having said that, there is no prohibition on redundantly specifying an access modifier which is also the default one, where there is a choice. For instance, a (concrete) method can be explicitly marked as private despite that being the default. The rule appears to be that where there is no choice (e.g. a method declaration in an interface) the redundant modifier is prohibited. Where there is a choice, it’s allowed.
There are many questions about this subject , but none (except one but still a short one) are dealing with the following scenario.
From C# 4 book:
Marc also wrote :
if you change the value of a const, you need to rebuild all the
clients
Question :
1) Why is that? Are both static readonly and const— static?
2) Where actually the values are saved ?
3) How does making a field static readonly actually solve this problem "behind the scene" ?
no, a const is a const, not a static - it is a special-case, with different rules; it is only set at compile-time (not runtime), and it is handled differently
the crux here is what the following means:
var foo = SomeType.StaticValue;
vs
var bar = SomeType.ConstValue;
in the first case, it reads the value at runtime from SomeType, i.e. via a ldsfld; however, in the second case, that is compiled to the value, i.e. if ConstValue happens to be 123, then the second is identical to:
var bar = 123;
at runtime, the fact that it came from SomeType does not exist, as the value (123) was evaluated by the compiler, and stored. Hence it needs a rebuild to pick up new values.
Changing to static readonly means that the "load the value from SomeType" is preserved.
So the following:
static int Foo()
{
return Test.Foo;
}
static int Bar()
{
return Test.Bar;
}
...
static class Test
{
public static readonly int Foo = 123;
public const int Bar = 456;
}
compiles as:
.method private hidebysig static int32 Bar() cil managed
{
.maxstack 8
L_0000: ldc.i4 0x1c8
L_0005: ret
}
.method private hidebysig static int32 Foo() cil managed
{
.maxstack 8
L_0000: ldsfld int32 ConsoleApplication2.Test::Foo
L_0005: ret
}
Note that in the Bar, the ldc is loading a value directly (0x1c8 == 456), with Test completely gone.
For completeness, the const is implemented with a static field, but - it is a literal field, meaning: evaluated at the compiler, not at runtime.
.field public static literal int32 Bar = int32(0x1c8)
.field public static initonly int32 Foo
if you change the value of a const, you need to rebuild all the clients
That is not the correct solution. If you change the value of a const then it was not a constant. Constants are by definition things that never change their value. The idea that you would change the value of a constant means that you are doing something logically impossible, and so of course things will break; you're doing something that you said you would not do. If you go around lying to the compiler, and it hurts when you do that, then stop lying to the compiler.
The price of gold is not a constant. The name of your bank is not a constant. The version number of your program is not a constant. These things change, so do not make them constants. Constants are things like pi, or the number of protons in an atom of gold.
Variables are things that can vary -- that's why they're called "variables". Constants are things that stay... constant. If it can vary, make it a variable. If it is constant, make it a constant. It is as simple as that.
why is that? both static readonly and const are static
Sure. What does that have to do with it? "static" in C# means "the named element is associated with the type, rather than with any particular instance of the type." ("Static" is therefore a poor choice of terms; VB does it better with "shared".)
Whether the name is associated with the type or an instance is irrelevant to the question of whether the name refers to a constant or variable.
where actually the values is being saved in both static readonly vsconst ?
When you use a constant value, the value is "baked in" wherever it is used. That's safe because it is never going to change. It's never going to change because it is constant, and that's what "constant" means.
When you use a variable, the variable's value is looked up at runtime every time. "readonly" just means "this variable can only be changed in the class constructor or field initializer". It is still a variable. (*)
how making a field static readonly - actually solve this problem behind the scene ?
You haven't stated what the problem is, so I don't know what problem you're trying to solve.
(*) Readonly fields are considered to be non-constant values outside the constructor, so that a readonly field of mutable value type cannot be mutated, and so that you cannot take a ref to a readonly field and then mutate the reference.
1) const is just resolved during compile time with the value that you have provided. While static readonly is a static variable.
2) static values are usually stored on a special area on the heap called High Frequency Heap. As I said previously consts are substituted at compile time.
3) making it static readonly will solve the problem because you will be reading a variable value at runtime, not a value provided at compile time.
You have already answered your question with the image you linked to. const fields will be compiled ("inlined") into the assembly - like a simple search and replace. static readonly means a normal field that is not allowed to change and exists only once in memory, but is still referenced by memory location.
In the .NET Framework, constants are not assigned a memory region, but
are instead considered values. Therefore, you can never assign a
constant, but loading the constant into memory is more efficient
because it can injected directly into the instruction stream. This
eliminates any memory accesses outside of the memory, improving
locality of reference. http://www.dotnetperls.com/optimization
I guess we can think of a constant as a hardcoded value in our code, but with better maintenance and usability offerings.
I got a bit of a surprise today when I changed the value of a publicly-visible constant in a static class and then replaced an old copy of the assembly with the newly-compiled version. The surprise was that the existing program that referenced the assembly didn't pick up the new value of the constant. That is, I didn't re-compile the executable but rather just replaced that one assembly.
A full description of my experiment is at How constant is a constant?
I'll admit to being very surprised by this behavior. I understand what's going on, but I don't understand why. Is there a particular technical reason why constants couldn't be picked up at JIT time rather than compile time? Are there cases where doing that would break things?
Constants are supposed to be constant. For all time. Constants are things like the value of pi, or the number of protons in a lead atom.
If your constant changes, it wasn't really a constant; use a readonly field instead.
Also see the Framework Design Guidelines, which state:
Use constant fields for constants that will never change. The compiler burns the values of const fields directly into calling code. Therefore const values can never be changed without the risk of breaking compatibility.
Essentially, changing a constant without recompiling everything that depends on it is every bit as broken as changing the signature of a method without recompiling everything that depends on it. The compiler "bakes in" all kinds of assumptions about information about metadata from referenced assemblies when it compiles a dependent assembly. If you make any change, you cannot expect things to simply keep on working.
There is also a third way to declare "constants": a public static property.
public static string ConstString {get{return "First test";}}
This has the versioning semantics of a readonly field, but if the jitter inlines the getter it becomes a jit-time constant. And unlike const it can be used on user defined types.
I think it's a good idea to use static properties for value-types and string, but not for user defined classes, since you don't want to allocate a new instance on each property access.
I used this in my FixedPoint type like this:
public struct FixedPoint
{
private int raw;
private const fracDigits=16;
private FixedPoint(int raw)
{
this.raw=raw;
}
public static FixedPoint Zero{get{return new FixedPoint();}}
public static FixedPoint One{get{return new FixedPoint(1<<fracDigits);}}
public static FixedPoint MaxValue{get{return new FixedPoint(int.MaxValue);}}
}
1) Why are member constants available even if there are no instances of a its class?
2) Is the only reason why constant expressions need to be fully evaluated at compile time due to compiler replacing constant variable with literal value?
3) Since string is also an object, I would think the following would produce an error, but it doesn’t. Why?
class A
{
const string b = “it works”;
}
thank you
Constants (declared with const) are implicitly static - hence no need for an instance.
A const value is embedded in the assembly it's declared in, and then every time it's used, that value is copied into the calling code as well. Therefore it can't be evaluated at execution time - if you want that behaviour, use static readonly.
String literals are constant values according to the C# language specification. Basically IL has a metadata representation for strings, allowing them to be specified as constants. String constants also have other interesting properties such as interning.
One point of interest: you can declare a decimal field as const in C#, but that doesn't really have CLR support... there's no literal form. The C# compiler fakes it using the [DecimalConstant] attribute. That's why you can't use decimal as an attribute argument type.