While the differences between writing an empty string as "" or as string.Empty are negligible, "" still creates a new object where string.Empty doesn't. So why doesn't the C# compiler optimize any occurrence of "" in one's code to string.Empty?
-
-
csc may not, but are you sure the CIL JIT compiler doesn't?
-
I'm not sure sure, but if I check the IL in reflector, string.Empty becomesW3bbo said:csc may not, but are you sure the CIL JIT compiler doesn't?L_0009: ldsfld string [mscorlib]System.String::Empty
whereas "" remainsL_0009: ldstr "" -
But "" doesn't create a new object because the .net string has an unmanaged constructor, the instance returned is the same as String.Empty because all string instances are pooled by the runtime.Bas said:
I'm not sure sure, but if I check the IL in reflector, string.Empty becomesW3bbo said:*snip*L_0009: ldsfld string [mscorlib]System.String::Empty
whereas "" remainsL_0009: ldstr "" -
stevo_ said:
But "" doesn't create a new object because the .net string has an unmanaged constructor, the instance returned is the same as String.Empty because all string instances are pooled by the runtime.Bas said:*snip*nearly true:using System;using System.Collections.Generic;public class MyClass{public static void Main(){// True - string literals are cachedConsole.WriteLine((object)"" == (object)"");// False - but are only pooled per assemblyConsole.WriteLine((object)"" == (object)string.Empty);// False - strings that are "constructed" at runtime are always new objectsConsole.WriteLine((object)"Hello World" == (object)String.Concat("Hello ","World"));// also FalseConsole.WriteLine((object)String.Concat("Hello ","World") == (object)String.Concat("Hello ","World"));// this depends on the compiler - a valid optimisation is to concat the strings together, at which point// this becomes the same as the first exampleConsole.WriteLine((object)"Hello World" == (object)("Hello " + "World"));Console.ReadLine();}} -
I think this may be like the case in SQL where an nvarchar with no text is like "" but you can not find (IN SQL) rows that have '' with the test for NULL.
NULL != ''
string.empty != ""
granted i think in many cases folks will see that as wrong but I bet there are places where it matters.... -
Back to your original question... My code written as:
static void Main(string[] args){string s = "";s = "" + s;}was compiled to:.entrypoint.maxstack 2.locals init ([0] string s)L_0000: nopL_0001: ldstr ""L_0006: stloc.0L_0007: ldloc.0L_0008: dupL_0009: brtrue.s L_0011L_000b: popL_000c: ldstr ""L_0011: stloc.0L_0012: retI don't see the String.Empty calls... -
littleguru said:Back to your original question... My code written as:static void Main(string[] args){string s = "";s = "" + s;}was compiled to:.entrypoint.maxstack 2.locals init ([0] string s)L_0000: nopL_0001: ldstr ""L_0006: stloc.0L_0007: ldloc.0L_0008: dupL_0009: brtrue.s L_0011L_000b: popL_000c: ldstr ""L_0011: stloc.0L_0012: retI don't see the String.Empty calls...
I'm not saying "" compiles to string.Empty. I'm asking why "" isn't compiled to string.Empty.
string.empty != ""
granted i think in many cases folks will see that as wrong but I bet there are places where it matters....
In what way is it different, and where does this matter? -
Sorry, I missread!Bas said:littleguru said:*snip*
In what way is it different, and where does this matter?
I send this question to a PM in the C# team. Let's see if we get an official response. -
Counter question: what are the benefits of turning every "" into a string.Empty?littleguru said:
Sorry, I missread!Bas said:*snip*
I send this question to a PM in the C# team. Let's see if we get an official response. -
Um, Console.WriteLine((object)"" == (object)string.Empty); returns true, at least on .NET 3.5 it does.evildictaitor said:stevo_ said:*snip*nearly true:using System;using System.Collections.Generic;public class MyClass{public static void Main(){// True - string literals are cachedConsole.WriteLine((object)"" == (object)"");// False - but are only pooled per assemblyConsole.WriteLine((object)"" == (object)string.Empty);// False - strings that are "constructed" at runtime are always new objectsConsole.WriteLine((object)"Hello World" == (object)String.Concat("Hello ","World"));// also FalseConsole.WriteLine((object)String.Concat("Hello ","World") == (object)String.Concat("Hello ","World"));// this depends on the compiler - a valid optimisation is to concat the strings together, at which point// this becomes the same as the first exampleConsole.WriteLine((object)"Hello World" == (object)("Hello " + "World"));Console.ReadLine();}}
Even if there was a performance difference, it's liable to be so microscopically small that it it's going to be meaningless in the long run. We are, after all, talking about creating one extra object for "", since the CLR would intern any further references to "" - hardly something worth losing sleep over. -
It's definitely False over here.AndyC said:
Um, Console.WriteLine((object)"" == (object)string.Empty); returns true, at least on .NET 3.5 it does.evildictaitor said:*snip*
Even if there was a performance difference, it's liable to be so microscopically small that it it's going to be meaningless in the long run. We are, after all, talking about creating one extra object for "", since the CLR would intern any further references to "" - hardly something worth losing sleep over.@figurres: string.empty != ""There's an ambiguous statement if ever I saw one. Using the string's overloaded == they are equal, but under object comparison they might not be.@littleguru:You'll save one heap object in the entire program and 12 bytes of space in your project. Downsides? Well you won't be able to compile against non-Microsoft implementations of the corlib. There's really no runtime benefit because string literals arn't copied to the heap when you use them, their value only exists on the heap if they are created at runtime (e.g. with String.Concat or String.Format) - string literals live on the string table. -
Like evildictator and AndyC said, it prevents unnecessary creation of one heap object. And as pointed out, the impact is negligible, I'm just curious why this microscopic performance boost (if there is one) isn't in the compiler. Just theoretically.littleguru said:
Counter question: what are the benefits of turning every "" into a string.Empty?littleguru said:*snip*
Personally, I always just use "". I find it easier to read than string.Empty, and premature optimization is evil. I've never been in want of a speed boost so badly that I replaced all my ""'s with string.Empty's.
In the same vein, what's faster? foo == "" or foo.Length > 0? -
Checking length is advised (fxcop and by extension the framework design guidelines talks about this), but they also go into recommending passing empty strings vs nulls etc.. in some cases you should use string.IsNullOrEmpty, which as you can imagine first checks for null then checks the length as zero..Bas said:
Like evildictator and AndyC said, it prevents unnecessary creation of one heap object. And as pointed out, the impact is negligible, I'm just curious why this microscopic performance boost (if there is one) isn't in the compiler. Just theoretically.littleguru said:*snip*
Personally, I always just use "". I find it easier to read than string.Empty, and premature optimization is evil. I've never been in want of a speed boost so badly that I replaced all my ""'s with string.Empty's.
In the same vein, what's faster? foo == "" or foo.Length > 0?
Equally checks basically run more code.. which is why its advised to check the length whenever you can, as large iterations of these checks can cause significant performance differences (aparently). -
Also I think its interesting to add that in the aparent not so far future (probably after .NET 4), the C# compiler will move to managed code, this will undoubtedly bring a ton of extension points and obviously a lot of metaprogramming features.. it would see highly likely that you can then do as many aspect orientated transforms + tweak / optimizations as you need with the extension points.
-
Because it would require the compiler to treat it as a special case - since String.Empty is a library feature (part of mscorlib) but isn't part of the language, compiler designers have (rightly in my opinion) avoided doing the optimisation.Bas said:
Like evildictator and AndyC said, it prevents unnecessary creation of one heap object. And as pointed out, the impact is negligible, I'm just curious why this microscopic performance boost (if there is one) isn't in the compiler. Just theoretically.littleguru said:*snip*
Personally, I always just use "". I find it easier to read than string.Empty, and premature optimization is evil. I've never been in want of a speed boost so badly that I replaced all my ""'s with string.Empty's.
In the same vein, what's faster? foo == "" or foo.Length > 0?With regards to whether to use "" versus String.Empty, I always assumed it was because extracting string literals is a common task for localization, and using String.Empty ensures that the localisation team don't have to distinguish between "" meaning no string and "" meaning don't print anything in this label and "" meaning something else - String.Empty is where the string is localization-independently empty.Also, (str.Length != 0) is the fastest way to check that the string is non-trivial, and avoid (as stevo_ says) passing nulls around.@stevo: extentions to the compiler are a sure-fire way of making the language unusable. If the C# code at Microsoft is different to the C# code at IBM which is different from every other 14 year old's C# code, then C# degrades from a multipurpose programming language to a nasty java-like scripting language. Optimisations are also something that won't readilly become available for the masses to program, because minor errors in an optimisation routine will mean that the code that is produced will do something different to what source-code says it will do, at which point people's confidence in C# as a language will be undermined.Everyone thinks that their extention, addon or optimisation is the best - that's why they're writing it (and this is also responsible for how every two-bit piece of software on the internet uses it's own skin and why every download program has it's own integrated browser, media player and takes ages to load). If you let everyone loose with language extentions, you'll wish you hadn't opened that pandora's box long before it morphs into a perl-like PHP with case-insensitivity, using runtime checked variants for everything and having an integrated eval function. -
evildictaitor said:
Because it would require the compiler to treat it as a special case - since String.Empty is a library feature (part of mscorlib) but isn't part of the language, compiler designers have (rightly in my opinion) avoided doing the optimisation.Bas said:*snip*With regards to whether to use "" versus String.Empty, I always assumed it was because extracting string literals is a common task for localization, and using String.Empty ensures that the localisation team don't have to distinguish between "" meaning no string and "" meaning don't print anything in this label and "" meaning something else - String.Empty is where the string is localization-independently empty.Also, (str.Length != 0) is the fastest way to check that the string is non-trivial, and avoid (as stevo_ says) passing nulls around.@stevo: extentions to the compiler are a sure-fire way of making the language unusable. If the C# code at Microsoft is different to the C# code at IBM which is different from every other 14 year old's C# code, then C# degrades from a multipurpose programming language to a nasty java-like scripting language. Optimisations are also something that won't readilly become available for the masses to program, because minor errors in an optimisation routine will mean that the code that is produced will do something different to what source-code says it will do, at which point people's confidence in C# as a language will be undermined.Everyone thinks that their extention, addon or optimisation is the best - that's why they're writing it (and this is also responsible for how every two-bit piece of software on the internet uses it's own skin and why every download program has it's own integrated browser, media player and takes ages to load). If you let everyone loose with language extentions, you'll wish you hadn't opened that pandora's box long before it morphs into a perl-like PHP with case-insensitivity, using runtime checked variants for everything and having an integrated eval function.
The compiler already uses library features. While writing a compiler, I learnt a lot about MSIL and .NET-based compilers. One thing I found out is that the .NET Framework has no support for decimal literals: the compiler generates code that calls one of the System.Decimal-constructors. Other library features that are used by the C# compiler are the IDisposable interface (using) and the IEnumerable interface(s) (foreach).Because it would require the compiler to treat it as a special case - since String.Empty is a library feature (part of mscorlib) but isn't part of the language, compiler designers have (rightly in my opinion) avoided doing the optimisation. -
I think you'll find project specific extensions become part of the compilation process.. these already happen today as part of 3rd party tools that pull apart IL and re-assemble it (post sharp for example). You seem to be confusing your process of building a compiler with what the extension points in the managed C# compiler will let you do.. its already been demonstated how the .NET C# compiler will work, being able to read source and get a tree that you can freely transform, or even build a tree manually (if you really wanted), then compilation units to take that tree and produce IL.evildictaitor said:
Because it would require the compiler to treat it as a special case - since String.Empty is a library feature (part of mscorlib) but isn't part of the language, compiler designers have (rightly in my opinion) avoided doing the optimisation.Bas said:*snip*With regards to whether to use "" versus String.Empty, I always assumed it was because extracting string literals is a common task for localization, and using String.Empty ensures that the localisation team don't have to distinguish between "" meaning no string and "" meaning don't print anything in this label and "" meaning something else - String.Empty is where the string is localization-independently empty.Also, (str.Length != 0) is the fastest way to check that the string is non-trivial, and avoid (as stevo_ says) passing nulls around.@stevo: extentions to the compiler are a sure-fire way of making the language unusable. If the C# code at Microsoft is different to the C# code at IBM which is different from every other 14 year old's C# code, then C# degrades from a multipurpose programming language to a nasty java-like scripting language. Optimisations are also something that won't readilly become available for the masses to program, because minor errors in an optimisation routine will mean that the code that is produced will do something different to what source-code says it will do, at which point people's confidence in C# as a language will be undermined.Everyone thinks that their extention, addon or optimisation is the best - that's why they're writing it (and this is also responsible for how every two-bit piece of software on the internet uses it's own skin and why every download program has it's own integrated browser, media player and takes ages to load). If you let everyone loose with language extentions, you'll wish you hadn't opened that pandora's box long before it morphs into a perl-like PHP with case-insensitivity, using runtime checked variants for everything and having an integrated eval function.
Thread Closed
This thread is kinda stale and has been closed but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.