page 1 of 2
Comments: 41 | Views: 922
Bas
Bas
It finds lightbulbs.
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?
W3bbo
W3bbo
The Master of Baiters
csc may not, but are you sure the CIL JIT compiler doesn't?
stevo_
stevo_
Human after all
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.
evildictaitor
evildictaitor
if( !succeed( try() ) ) { while(true) try(); }

nearly true:

using System;
using System.Collections.Generic;

public class MyClass
{
public static void Main()
{
// True - string literals are cached
Console.WriteLine((object)"" == (object)"");
// False - but are only pooled per assembly
Console.WriteLine((object)"" == (object)string.Empty);
// False - strings that are "constructed" at runtime are always new objects
Console.WriteLine((object)"Hello World" == (object)String.Concat("Hello ","World"));
// also False
Console.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 example
Console.WriteLine((object)"Hello World" == (object)("Hello " + "World"));
Console.ReadLine();
}
}
figuerres
figuerres
???
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....
littleguru
littleguru
<3 Seattle
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: nop 
L_0001: ldstr ""
L_0006: stloc.0 
L_0007: ldloc.0 
L_0008: dup 
L_0009: brtrue.s L_0011
L_000b: pop 
L_000c: ldstr ""
L_0011: stloc.0 
L_0012: ret 

I don't see the String.Empty calls...
littleguru
littleguru
<3 Seattle
Sorry, I missread! Sad

I send this question to a PM in the C# team. Let's see if we get an official response.
littleguru
littleguru
<3 Seattle
Counter question: what are the benefits of turning every "" into a string.Empty?
Um, Console.WriteLine((object)"" == (object)string.Empty); returns true, at least on .NET 3.5 it does.

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. 
evildictaitor
evildictaitor
if( !succeed( try() ) ) { while(true) try(); }
It's definitely False over here.

@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.
stevo_
stevo_
Human after all
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..

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).
stevo_
stevo_
Human after all
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.
evildictaitor
evildictaitor
if( !succeed( try() ) ) { while(true) try(); }
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.

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.
TommyCarlier
TommyCarlier
I want my scalps!
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.
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).
stevo_
stevo_
Human after all
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.
stevo_
stevo_
Human after all

Actually I don't think the C# compiler is aware of IEnumerable (I could be wrong), the foreach really just looks for a member called GetEnumerator() that returns an object that has the members MoveNext and Current (with applicable access and signatures).

evildictaitor
evildictaitor
if( !succeed( try() ) ) { while(true) try(); }
Those are defined as part of the C# Ecma specification. String.Empty isn't.

The compiler demands all of the primitives (byte,sbyte,char,string,int16,int32,int64,uint16,uint32,uint64,intptr,uintptr,bool and void), the metatypes (delegate, multicastdelegate, valuetype,object,enum,array), some special types (exception, runtimehandles) some compiler directives (paramsarrayattribute,outattribute) and the interfaces IEnumerable, IDisposable, IEnumerator (with appropriate types on the interfaces) to be defined as part of the ECMA standard for C#. Most everything else in C# is library and syntax sugar.
Interesting discussion, learning a lot from this.
Sven Groot
Sven Groot
My name has 9 letters. Coincidence? I think not...
It's definitely False over here.

It's true here, Vista x64, .Net 3.5 SP1.

As for str == "" versus str.Length == 0, I've always been told the latter performs better though I've never checked it myself. If there's a chance of str being null, using string.IsNullOrEmpty(str) is best of course.

Visual Basic throws some mud into the water since doing str = "" (comparison, not assignment) is actually treated as a special case by the compiler which also evaluates true if str is null (Nothing), similar to string.IsNullOrEmpty(). I never know whether I should comment on that when I use it, since it's a language feature and I don't like writing comments to explain language features, but very few people actually know about this one, and C# developers trying to read VB code will definitely not know about it and might think it's a bug.
littleguru
littleguru
<3 Seattle
Well... it depends. Since even comparing "" with string.Empty by calling the object.ReferenceEquals method returns true they both might actually represent the same objects on the heap... this could be optimized inside the CLR.

All the checks of evildictaitor result in "true" for me over here (same as Sven)... .NET 3.5 SP1 x86
littleguru
littleguru
<3 Seattle
Well try foreach on an object that has not the IEnumerable interface implemented but rather only exposes a GetEnumerator method... will work fine. Nice hack, isn't it?
page 1 of 2
Comments: 41 | Views: 922
Microsoft Communities