210

In .NET why is String.Empty read only instead of a constant? I'm just wondering if anyone knows what the reasoning was behind that decision.

Andreas
  • 5,393
  • 9
  • 44
  • 53
travis
  • 35,751
  • 21
  • 71
  • 94
  • 7
    [This](http://stackoverflow.com/questions/8485515/meaning-of-confusing-comment-above-string-empty-in-net-bcl-source/8487944#8487944) question can solve this one, the brief answer is, no one knows... – gdoron Dec 15 '11 at 07:37
  • 1
    Particularly given that Decimal.Zero is const (from the user perspective that is ...) – Hamish Grubijan Mar 12 '12 at 23:01

4 Answers4

165

The reason that static readonly is used instead of const is due to use with unmanaged code, as indicated by Microsoft here in the Shared Source Common Language Infrastructure 2.0 Release. The file to look at is sscli20\clr\src\bcl\system\string.cs.

The Empty constant holds the empty string value. We need to call the String constructor so that the compiler doesn't mark this as a literal.

Marking this as a literal would mean that it doesn't show up as a field which we can access from native.

I found this information from this handy article at CodeProject.

Jeff Yates
  • 61,417
  • 20
  • 137
  • 189
  • 1
    I would really appreciate if you can explain this comment (because Jon Skeet couldn't...) see here:http://stackoverflow.com/questions/8462697/what-are-native-and-literal-keywords – gdoron Dec 12 '11 at 02:09
  • 2
    @gdoron: My guess (and it is a guess) is this. When a value is defined as a literal (a constant) its value is inserted in the places where it is referenced whereas when it is not defined as a literal, the source of the value is referenced and the actual value is retrieved at runtime. I suspect that the latter may ensure that proper marshalling of the string occurs between native and .NET at runtime - if it were a literal, perhaps the native compiler would need to somehow pull the literal value into its native code, which probably isn't feasible. This is all conjecture on my part, though. – Jeff Yates Dec 12 '11 at 14:28
  • 7
    It does mean that one has to use "", rather than string.Empty for default parameter values in methods. Which is slightly annoying. – nicodemus13 Oct 17 '12 at 21:03
  • 18
    "" can look like a mistake, while string.Empty shows deliberate intention – Christopher Stevenson May 17 '13 at 12:05
  • 5
    @JeffYates I'd add that the fact that it's not consistent is already annoying. People would see the rest of the code and wonder "why is he using "" here instead of String.Empty?". I'm seriously considering not using `String.Empty` anymore for that reason alone. – julealgon Aug 04 '14 at 14:53
28

I think there is a lot of confusion and bad responses here.

First of all, const fields are static members (not instance members).

Check section 10.4 Constants of the C# language specification.

Even though constants are considered static members, a constant-declaration neither requires nor allows a static modifier.

If public const members are static, one could not consider that a constant will create a new Object.

Given this, the following lines of code do exactly the same thing in respect to the creation of a new Object.

public static readonly string Empty = "";
public const string Empty = "";

Here is a note from Microsoft that explains the difference between the 2:

The readonly keyword is different from the const keyword. A const field can only be initialized at the declaration of the field. A readonly field can be initialized either at the declaration or in a constructor. Therefore, readonly fields can have different values depending on the constructor used. Also, while a const field is a compile-time constant, the readonly field can be used for runtime constants, ...

So I find that the only plausible answer here is Jeff Yates's.

bruno conde
  • 47,767
  • 15
  • 98
  • 117
  • +1 for the kind words and clarification regarding C# spec on const and static readonly. – Jeff Yates Feb 03 '09 at 17:46
  • 24
    Re-reading this, I disagree that `const string` and `static readonly string` do the same thing. Const values are substituted in linked code whereas static readonly values are referenced. If you have a `const` in library A that is used by library B, library B will replace all references to that `const` variable with its literal value; if that variable were `static readonly` instead, it would be referenced and its value determined at runtime. – Jeff Yates Aug 16 '12 at 13:51
  • 7
    Jeff's point is important when referencing libraries. If you you recompile A and redistribute it, *without recompiling B*, B will still be using the old values. – Mark Sowul Feb 03 '13 at 22:43
7
String.Empty read only instead of a constant?

If you make any string constant, then the compiler is replace with the actually string everywhere you call it and you fill your code with the same string all over and when the code runs is also need to read again and again that string from the different memory data.

If you leave your string read only on one place as it is the String.Empty, the program keep the same string only on one place and read it, or refer to it - keeping the data in memory minimum.

Also if you compile any dll using the String.Empty as const, and for any reason the String.Empty change, then the compiled dll will not work any more the same, because the cost make the inside code to actually keep a copy of the string on every call.

See this code for example:

public class OneName
{
    const string cConst = "constant string";
    static string cStatic = "static string";
    readonly string cReadOnly = "read only string";

    protected void Fun()
    {
        string cAddThemAll ;

        cAddThemAll = cConst;
        cAddThemAll = cStatic ;
        cAddThemAll = cReadOnly;    
    }
}

will be come by the compiler as:

public class OneName
{
    // note that the const exist also here !
    private const string cConst = "constant string";
    private readonly string cReadOnly;
    private static string cStatic;

    static OneName()
    {
        cStatic = "static string";
    }

    public OneName()
    {
        this.cReadOnly = "read only string";
    }

    protected void Fun()
    {
        string cAddThemAll ;

        // look here, will replace the const string everywhere is finds it.
        cAddThemAll = "constant string";
        cAddThemAll = cStatic;
        // but the read only will only get it from "one place".
        cAddThemAll = this.cReadOnly;

    }
}

and the assembly call

        cAddThemAll = cConst;
0000003e  mov         eax,dword ptr ds:[09379C0Ch] 
00000044  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cStatic ;
00000047  mov         eax,dword ptr ds:[094E8C44h] 
0000004c  mov         dword ptr [ebp-44h],eax 
        cAddThemAll = cReadOnly;
0000004f  mov         eax,dword ptr [ebp-3Ch] 
00000052  mov         eax,dword ptr [eax+0000017Ch] 
00000058  mov         dword ptr [ebp-44h],eax 

Edit: Corrected typo

Vitani
  • 1,594
  • 1
  • 14
  • 28
Aristos
  • 66,005
  • 16
  • 114
  • 150
  • So, this means that the const string has to be always instantiated with the class containing that const? That seems like it's much better to use static readonly then. – the berserker Jun 27 '16 at 07:45
  • @theberserker well is better, but you have all options to use. – Aristos Jun 28 '16 at 08:35
  • 1
    > then the compiled dll will not work any more the same, because the cost make the inside code to actually keep a copy of the string on every call. @Aristos That's not quite right. Once the code is compiled, it the "copy" of the string will be referenced in the TEXT block of the executable, and all code will just reference that same block of memory. What you cited in your second step is simply an intermediate step. – Peter Dolkens Aug 04 '16 at 11:38
  • @user1533523 thank you for the note - I will make a test when I find some time to check this out – Aristos Aug 04 '16 at 11:41
  • How did you get that assembly code? C# does not compile to assembly! – jv110 Feb 24 '18 at 01:05
  • @jv110 Stop (break point) with debugger there (if I remember well), and ask to show me the assembly code. – Aristos Feb 24 '18 at 07:45
  • @PeterDolkens is correct. The compiler will use the same instance throughout the code. You can do a very simple ReferenceEquals() check to see that this is the case. – aaronburro Aug 04 '22 at 20:26
  • @aaronburro I say the same – Aristos Aug 05 '22 at 07:20
-1

This answer exists for historical purposes.

Originally:

Because String is a class and therefore cannot be a constant.

Extended Discussion:

A lot of useful dialog was hammered out in vetting this answer, and rather than deleting it, this content is reproduced directly:

In .NET, (unlike in Java) string and String are exactly the same. And yes, you can have string literal constants in .NET – DrJokepu Feb 3 '09 at 16:57

Are you saying that a Class cannot have constants? – StingyJack Feb 3 '09 at 16:58

Yes, objects have to use readonly. Only structs can do constants. I think when you use string instead of String the compiler changes the const into a readonly for you. All to do with keeping C programmers happy. – Garry Shutler Feb 3 '09 at 16:59

tvanfosson just explained it a little bit more verbose. "X cannot be a constant, because the containing Y is a class" was just a little bit too context-free ;) – Leonidas Feb 3 '09 at 17:01

string.Empty is static property that returns an instance of the String class, namely the empty string, not the string class itself. – tvanfosson Feb 3 '09 at 17:01

Empty is a readonly instance (it's not a property) of the String class. – senfo Feb 3 '09 at 17:02

Head hurting. I still think I'm right, but now I'm less certain. Research required tonight! – Garry Shutler Feb 3 '09 at 17:07

The empty string is an instance of the string class. Empty is a static field (not a property, I stand corrected) on the String class. Basically the difference between a pointer and the thing it points to. If it weren't readonly we could change which instance the Empty field refers to. – tvanfosson Feb 3 '09 at 17:07

Garry, you don't need to do any research. Think about it. String is a class. Empty is an instance of a String. – senfo Feb 3 '09 at 17:12

There is something I don't quite get: how on earth can the static constructor of the String class create an instance of the String class ? Isn't that some sort of "chicken or the egg" scenario? – DrJokepu Feb 3 '09 at 17:12 5

This answer would be correct for nearly any other class but System.String. .NET does a lot of performance special-casing for strings, and one of them is that you CAN have string constants, just try it. In this case, Jeff Yates has the correct answer. – Joel Mueller Feb 3 '09 at 19:25

As described in §7.18, a constant-expression is an expression that can be fully evaluated at compile-time. Since the only way to create a non-null value of a reference-type other than string is to apply the new operator, and since the new operator is not permitted in a constant-expression, the only possible value for constants of reference-types other than string is null. The previous two comments were taken directly from the C# language specification and reiterate what Joel Mueller mentioned. – senfo Feb 4 '09 at 15:05 5

Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
Garry Shutler
  • 32,260
  • 12
  • 84
  • 119
  • Please, vote down the correct answer. If you Goto Definition, you'll find that it is on the String class and is an instance of String. The fact that it shows as lower case is compiler magic. – Garry Shutler Feb 03 '09 at 16:54
  • It wasn't me who downvoted you but in .NET, (unlike in Java) string and String are exactly the same. And yes, you can have string literal constants in .NET – Tamas Czinege Feb 03 '09 at 16:57
  • I didnt DV you, but can you humor me a bit. Are you saying that a Class cannot have constants? – StingyJack Feb 03 '09 at 16:58
  • Yes, objects have to use readonly. Only structs can do constants. I think when you use string instead of String the compiler changes the const into a readonly for you. All to do with keeping C programmers happy. – Garry Shutler Feb 03 '09 at 16:59
  • tvanfosson just explained it a little bit more verbose. "X cannot be a constant, because the containing Y is a class" was just a little bit too context-free ;) – Leonidas Feb 03 '09 at 17:01
  • string.Empty is static property that returns an instance of the String class, namely the empty string, not the string class itself. – tvanfosson Feb 03 '09 at 17:01
  • Empty is a readonly **instance** (it's not a property) of the String class. – senfo Feb 03 '09 at 17:02
  • Head hurting. I still think I'm right, but now I'm less certain. Research required tonight! – Garry Shutler Feb 03 '09 at 17:07
  • The empty string is an instance of the string class. Empty is a static field (not a property, I stand corrected) on the String class. Basically the difference between a pointer and the thing it points to. If it weren't readonly we could change which instance the Empty field refers to. – tvanfosson Feb 03 '09 at 17:07
  • Garry, you don't need to do any research. Think about it. String is a class. Empty is an instance of a String. – senfo Feb 03 '09 at 17:12
  • There is something I don't quite get: how on earth can the static constructor of the String class create an instance of the String class ? Isn't that some sort of "chicken or the egg" scenario? – Tamas Czinege Feb 03 '09 at 17:12
  • 11
    This answer would be correct for nearly any other class but System.String. .NET does a lot of performance special-casing for strings, and one of them is that you CAN have string constants, just try it. In this case, Jeff Yates has the correct answer. – Joel Mueller Feb 03 '09 at 19:25
  • As described in §7.18, a constant-expression is an expression that can be fully evaluated at compile-time. – senfo Feb 04 '09 at 15:00
  • (continued) Since the only way to create a non-null value of a reference-type other than string is to apply the new operator, and since the new operator is not permitted in a constant-expression, the only possible value for constants of reference-types other than string is null. – senfo Feb 04 '09 at 15:01
  • The previous two comments were taken directly from the C# language specification and reiterate what Joel Mueller mentioned. – senfo Feb 04 '09 at 15:05
  • 7
    I nearly deleted this answer as a much better one came along, but the discussion in these comments is worth keeping. – Garry Shutler Feb 04 '09 at 16:38
  • 1
    @Garry, you're lucky I read your last comment, otherwise I would also downvote. A string has a special feature in .NET, that eventho it's a ref class it can be a const. – Shimmy Weitzhandler Feb 14 '11 at 23:59