Scott Hanselman

Back to Basics - Do namespace using directives affect Assembly Loading?

July 04, 2008 Comment on this post [29] Posted in Back to Basics
Sponsored By

Jeff Atwood had a great post a while back called "Strong Opinions, Weakly Held." It's good to feel strongly about something, but important to be open to changing your opinion if you're faced with new evidence.

Last week a reader pointed me to this post at the Microsoft StyleCop blog that shows some interesting examples of using directives outside and inside the namespace declaration.

For example, this compiles fine:

using Guid = System.Guid;

namespace Microsoft.Sample
{
public class Guid
{
public Guid(string s){}
}

public class Program
{
public static void Main(string[] args)
{
Guid g = new Guid("hello");
}
}

}

However this one with the using moved inside the namespace doesn't compile:

namespace Microsoft.Sample
{
using Guid = System.Guid;

public class Guid
{
public Guid(string s){ }
}

public class Program
{
public static void Main(string[] args)
{
Guid g = new Guid("hello");
}
}
}

The code fails on the following compiler error, found on the line containing Guid g = new Guid("hello");

CS0576: Namespace 'Microsoft.Sample' contains a definition conflicting with alias 'Guid'

In the first example, there's an alias created, but it doesn't matter because the second Guid class is in local scope (there's no scope conflict) and the compiler chooses the inner Guid class.

In the second example, there are two "Guids" declared in the same scope and that's a conflict that the compiler can't resolve automatically. The style rule/argument the post makes is that you will only see these kinds of conflicts if you put your using directives inside your namespaces. To this, I say, "meh." Sure, if it makes you happy and you use lots of namespace aliases, sure, but it's an edge case. I simply prefer to have my namespaces outside.

Read Twice, Test Once

However, the second rule in the post said:

"However, placing the using statements [Ed. Note: They mean "directives"] within a namespace element allows the framework to lazy load the referenced assemblies at runtime. In some cases, if the referencing code is not actually executed, the framework can avoid having to load one or more of the referenced assemblies completely. This follows general best practice rule about lazy loading for performance."

This stopped me in my tracks. This rocks the very bedrock that my knowledge of the CLR stands on. I'm like, NO WAY, and then I oscillated back and forth between denial and acceptance. Then, I settled on denial. I don't buy it. A using directive is for aliasing and is a kind of syntactic sugar. Ultimately the IL is the same. Assembly loading won't be affected as the assembly manifest doesn't change.

Here's what my experiment showed. I believe it's true until I find out from someone on the CLR Loader team that it's not true. ;)

First Test

using System;
using System.Xml;

namespace Microsoft.Sample
{
public class Program
{
public static void Main(string[] args)
{
Guid g = Guid.NewGuid();
Console.WriteLine("Before XML usage");
Console.ReadLine();
Foo();
Console.WriteLine("After XML usage");
Console.ReadLine();
}

public static void Foo()
{
XmlDocument x = new XmlDocument();
}
}
}

I ran this program outside the debugger but compiled in debug mode. At the point there the first ReadLine() hits, the program pauses and waits for an Enter key. I loaded up Process Explorer and saw:

image

Then, I hit Enter, executing the Foo() method and new'ing up an XmlDocument. You can see that System.Xml just got loaded (specifically the native image) into the process.

image

Second Test

If I do the same thing with the usings INSIDE the namespace I get identical results.

namespace Microsoft.Sample
{
using System;
using System.Xml;

public class Program
{
public static void Main(string[] args)
{
Guid g = Guid.NewGuid();
Console.WriteLine("Before XML usage");
Console.ReadLine();
Foo();
Console.WriteLine("After XML usage");
Console.ReadLine();
}

public static void Foo()
{
XmlDocument x = new XmlDocument();
}
}
}

In fact, the only thing that changed the way the assemblies got loaded was switching to release mode. Running the app in release mode had all the assemblies in my trivial app loaded immediately. I thought it was weird for a second, but then realized it had nothing to do with debug vs. release. It was simply that the Foo() method was either inlined or there was a Tail Call Optimization as I explored in this post: Release IS NOT Debug: 64bit Optimizations and C# Method Inlining in Release Build Call Stacks.

I'm 99.99% sure at this point that using directives can't change your assembly loading behavior and I think I was right to be suspicious. However, I'm going to ask some people on the Fusion (assembly loader) and C# teams who are smarter than I and I'll update this post as I learn more!

However, the Back to Basics Tips here are:

  • Don't believe everything you read, even on a Microsoft Blog.
  • Don't believe this blog, either!
  • Decide for yourself with experiments if you need a tiebreaker!

And be ready to be wrong anyway! It only takes one negative experiment to disprove a theory. Of course, the real question is, what does the specification say? 

UPDATE #1: Ian Griffiths had a similar reaction and a similar test!

What do you think, Dear Reader?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. He is a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Hosting By
Hosted in an Azure App Service
July 04, 2008 21:46
I'm with you. My understand is that assemblies are always lazy loaded anyway, in that they aren't loaded until a method that uses of it's types is jitted. I've never heard of Using directives affecting that in any way.
July 04, 2008 22:15
I read and thought the same thing when I saw that a couple days ago, nice to know that testing shows it as well. Please do get in touch with someone who worked on the compiler and happens to know the reasoning for it (a separate post would be better than an update though).

Rules like this are one reason I've decided that I don't really like stylecop.

July 04, 2008 22:23
Phew!

I saw the same thing and thought, "no way! That can't be right. That means everybody's been doing it the wrong way for years"

There's just no way everybody would do it wrong that long.

Plus the "wrong" way looks better.
July 05, 2008 0:29
I don't know if it's still the internal standard @ MS, but Brad Abrams also mentions that "Using statements should be inside the namespace declaration. (section 2.8)" here: http://blogs.msdn.com/brada/articles/361363.aspx

StyleCop documentation also mentions "Note, this is subject to change as the .Net Framework evolves, and there are subtle differences between the various versions of the framework.", so it might be a safeguard to devise a rule to cover different framework versions.
July 05, 2008 0:30
The other test you can do: run ILDASM against the compiler output and compare the difference.

You'll find the position of the using statement has no impact on the IL. (This means you won't need to bother the fusion team.)

The IL and metadata in a .NET assembly doesn't actually have anything corresponding to namespaces. Namespaces are really just a synthetic construct built on top of a naming convention for classes.
July 05, 2008 0:32
Seeing as how there isn't an IL equivalent of a using directive, I don't see how that could even be possible. One thing that I do know is that the JScript.NET compiler ( *not* a compiled assembly that happened to have been compiled from JScript .NET code) will try to auto-resolve references based on your import statements but that's a compile time thing and has nothing to do with assembly loading. Not to mention it has nothing to do with placement. :)
July 05, 2008 1:02
I don't buy this at all. If you add a reference to an assembly in your project, then add using directives all willy nilly, but not actually using any of the types in that assembly, that assembly won't get loaded. As such, I don't believe the using directives have any effect whatsoever on the *loading* of the assemblies, as much as they have on the source code as such.

Even the msdn help on the using directive:
http://msdn.microsoft.com/en-us/library/sf0df423.aspx

doesn't say anything about *loading* the assembly, it just says it gives you, quote: "To allow the use of types in a namespace so that you do not have to qualify the use of a type in that namespace".

No, I don't buy this.
July 05, 2008 1:35
I agree. Don't trust everything. But trust somethings, otherwise you're just gonna go nuts, checking every little thing. And when you need something to be true, because otherwise you or the project is going to have some bad impact, just check, as you wrote.
Regarding the actual problem, for me the directives are just syntactic sugar, really... I didn't check, but what does the IL say?
July 05, 2008 1:35
I agree with you Scott,but if possible please check with the team and let us know.

Its always best thing to know the basics very.

Thanks,
Yash
July 05, 2008 3:21
In fact, I would go one further and claim that if assembly loading is controlled by using statements instead of type resolution, it won't be possible to do much lazy assembly loading at all.

Imagine a simple scenario where assembly A references assembly B, which implements namespace N. The first using N; statement in assembly A sources would cause loading assembly B, according to that rule.

Now, let's add assembly C, which also implements classes in namespace N. It also implements classes in namespace O as well. Assembly A references C, but uses only classes from namespace O. However, that same using N; statement now should cause the runtime to load assembly C as well.

To make things even worse, we'll add assembly D, which implements namespace P. Assembly C references D and has using P; statement. Even if that statement is inside the namespace N portion, the first use of any class in namespace N implemented by assembly B should cause the assembly D to be loaded as well. After all, code inside namespace N is being executed, so according to the rule explanation this nested using statements should cause loading the assemblies implementing these namespaces. It shouldn't matter that the code excecuted is in assembly B and the using P; statement is inside assembly C; it's in the same namespace N and namespaces are not assembly bound like the types.

On the other hand, if assemblies are being lazy loaded at type resolution, the runtime will have it a lot easier.

Of course, I am not on the CLR or the Fusion teams, so I can't claim I know what I am talking about... :-)
July 05, 2008 4:01
It's a very common misconception that there is a connection between namespaces and DLLs.
July 05, 2008 13:37
Namespaces have no existence in IL code. If you look at metadata, there is no namespace table as there are some type, field, method tables. Actually, we (human) consider that 2 types are in the same namespaces just because their names (i.e namespace.type) is prefixed by the same namespace string. But the CLR doesn't care if 2 types are in the same namespaces or not.

In this condition, the order of declaration of using directives won't change the way assemblies are loaded at runtime. Maybe you could show with reflector that the IL produce is the same, or even better, you could show that the assembly 2 files are identical, bytes per bytes.
July 05, 2008 19:34
When the JIT inspects a method for inlining, it loads the assembly in the process.... even if the inlining fails!
July 06, 2008 8:42
Test
July 06, 2008 10:12
Nice post thanks!!
July 06, 2008 16:01
I'm a dev on the .NET Compact Framework team. I debugged through our loader code and I can confirm that " using directives do not change your assembly loading behavior". I'm writing a post on it now and will publish by tomorrow.
July 06, 2008 16:21
"Note, this is subject to change as the .Net Framework evolves, and there are subtle differences between the various versions of the framework." Man, I hate when people make statements like that and then don't follow up with details or at least a pointer to some reference.
July 06, 2008 22:21
Sorry, but the discussion is irrelevant, since the Microsoft Code Style-guidelines tells you to put your "using"-directives inside the namespace :)
July 06, 2008 22:34
Seb - I don't see how that makes the discussion irrelevant. Every sample I (and likely you) have ever seen has them outside, so it's fair to say that's the defacto standard. Even internally to Microsoft the standard is outside. I'm not sure where the StyleCop teams comes up with their styles. Certainly, it's safer to put them inside if you're one who uses multiple types in a single code file (not my style) and you use a lot of aliases.

Still, the point of the post is the loader claim, which appears specious, rather than the style issues.
July 07, 2008 8:16
Very interesting, Scott. I was intrigued to conduct my own experiments for my own first-hand experience. Here' what I observed. Code sample #1

using System;

namespace wheretoplaceusing
{
using System.Xml;

class Program
{
static void Main(string[] args)
{
Console.WriteLine("Press enter to load XmlDocument.");
Console.ReadLine();
LoadXml();
Console.WriteLine("XmlDocument created.");
Console.ReadLine();
}

static void LoadXml()
{
XmlDocument xmlDoc = new XmlDocument();
}

}
}

Compiled in debug mode, it ran without loading System.Xml.dll assemblies until I hit Enter.

The IL for the Main method looked like

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 42 (0x2a)
.maxstack 8
IL_0000: nop
IL_0001: ldstr "Press enter to load XmlDocument."
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: call string [mscorlib]System.Console::ReadLine()
IL_0011: pop
IL_0012: call void wheretoplaceusing.Program::LoadXml()
IL_0017: nop
IL_0018: ldstr "XmlDocument created."
IL_001d: call void [mscorlib]System.Console::WriteLine(string)
IL_0022: nop
IL_0023: call string [mscorlib]System.Console::ReadLine()
IL_0028: pop
IL_0029: ret
} // end of method Program::Main


Code sample #2

using System;
using System.Xml;

namespace wheretoplaceusing
{

class Program1
{
static void Main(string[] args)
{
Console.WriteLine("Press enter to load XmlDocument.");
Console.ReadLine();
XmlDocument xmlDoc = new XmlDocument();
LoadXml();
Console.WriteLine("XmlDocument created.");
Console.ReadLine();
}

static void LoadXml()
{
XmlDocument xmlDoc = new XmlDocument();
}
}

}

Also compiled in debug mode, but System.Xml assemblies get loaded immediately on program launch. The difference? The IL main method got inlined.

.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 48 (0x30)
.maxstack 1
.locals init ([0] class [System.Xml]System.Xml.XmlDocument xmlDoc)
IL_0000: nop
IL_0001: ldstr "Press enter to load XmlDocument."
IL_0006: call void [mscorlib]System.Console::WriteLine(string)
IL_000b: nop
IL_000c: call string [mscorlib]System.Console::ReadLine()
IL_0011: pop
IL_0012: newobj instance void [System.Xml]System.Xml.XmlDocument::.ctor()
IL_0017: stloc.0
IL_0018: call void wheretoplaceusing.Program1::LoadXml()
IL_001d: nop
IL_001e: ldstr "XmlDocument created."
IL_0023: call void [mscorlib]System.Console::WriteLine(string)
IL_0028: nop
IL_0029: call string [mscorlib]System.Console::ReadLine()
IL_002e: pop
IL_002f: ret
} // end of method Program1::Main

It is interesting to note how the mere placement of a Using statement, which I thought was purely for Visual Studio code editing purposes, actually influences the compiler to generate different IL.
July 07, 2008 8:21
Heck, IGNORE THE ABOVE OBSERVATION.

I realised a fault in my second code block, where I forgot to remove the redundant XmlDocument line in the Main method, causing the "inlining" when i peeked at the IL. This caused the System.Xml assemblies to be loaded prematurely.
July 07, 2008 13:38
Nice work Scott. Now comment up the StyleCop blog so everyone who reads it knows.
Ben
July 07, 2008 13:39
Boo, they have disabled comments.
Ben
July 07, 2008 19:55
Yes I admit that I was the one who blindly passed along this misinformation. However, I did prefix it by saying that I hadn't tested it myself so it might be a snipe hunt. :P
July 07, 2008 23:20
All of the following new file templates in visual studio 2005 puts using statements outside the namespace declaration. I did not see any that put the using statement inside the namespace declaration.

Class definition, class declaration, custom control, debugger visualizer, windows form, inherited form, component class, windows service, interface, user control, installer class

As I recall, in Visual studio 7 there was at least one template that put the usings inside the namespace declaration. I can't remember which one(s). But even then a class definition template put the usings outside the namespace declaration.

I'd consider usings outside the namespace as the standard. The edge case of needing more than one namespace per file can always opt to move the usings inside each namespace when there are differences. Even then I'd put the common ones outside the namespace declaration to reduce redundency.

There is a simple solution to problem 1 (Type Confusion). Don't name your alias the same as any known class name. As a general rule I use abbreviations when creating an alias, and don't use abbreviations when naming a class.

using SWUIWC = System.Web.UI.WebControls;
July 08, 2008 16:29
Ah crap, and to think I just refactored all the C# code I'd ever written based on that blog entry :)

Seriously though, after falling off my chair, my next thought would have been 'and what if I fully qualify type names - what then?'
July 10, 2008 19:03
Have you found out anything more about this? It is pretty disturbing for this kind of misinformation to be posted on an MS blog. Not to mention that it makes me wonder what other bad assumptions the StyleCop creators were laboring under when they created their rules...
July 11, 2008 1:00
Yes, they were mistaken, and they removed that section from the blog post.
July 23, 2008 0:20
Well well, it seemed obvious to me that placing the "using" either outside or inside the namespace wouldn't modify the way assemblies are loaded... but I must confess I didn't take time to test by myself. Because I'm a really lazy person, I will rather suggest a complementary test: what happens if there is no "using System.Xml;" at all and you write explicitly this ;-) :

System.Xml.XmlDocument x = new System.Xml.XmlDocument();

Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.