namespace - a short expose


This is reproduced from the June 1995 issue of Overload.
So far, very few compilers support namespaces. Metaware's is, I believe, the only commercially available compiler at present although several vendors are working on them. This means that we have no experience of working with them at all. I shall present a few short code examples showing how the draft standard says they will work and ask you for your comments.

	namespace A {
		int j;
	}
	void f()
	{
		j = 1;  // error: no j in scope
	}
	void g()
	{
		using namespace A;
		j = 1;  // fine: finds A::j
	}

Even without explaining the rules to you, this is probably intuitive.


Let's look at a more complex example:

	namespace A {
		int j;
	}
	int j;
	void f()
	{
		j = 1;  // fine: finds global ::j
	}
	void g()
	{
		using namespace A;
		j = 1;  // ambiguous: ::j or A::j?
	}

Does that surprise you? Let me explain the rule for lookup: scopes are searched for a name and if the global scope is reached, any namespaces specified with a using directive are "unlocked" and also searched.


A more complicated example will see whether we understand that:

	namespace A {
		int j;
	}
	int j;
	void f()
	{
		int j = 0;
		if (j)  // fine: local j
		{
			using namespace A;
			j = 0;  // finds local j
		}
	}

The scopes are searched outwards and the local variable j is found. Since we didn't reach the global scope, no namespaces were unlocked.


What about when one namespace uses another?

	namespace A {
		int j;
	}
	namespace B {
		using namespace A;
		int k;
	}
	void f()
	{
		using namespace B;
		j = 0;  // fine: A::j
	}

This is because the namespace lookup is transitive - once one namespace is unlocked for lookup, any other namespaces mentioned are also unlocked. In particular if B had defined another variable j in the above example, the use of j in f would have been ambiguous: B::j or A::j. Note, however, that in the example as written, j is not a member of B so the following will not work [according to the April 95 draft]:

	namespace A {
		int j;
	}
	namespace B {
		using namespace A;
		int k;
	}
	void f()
	{
		B::k = 0;  // fine: k is member of B
		B::j = 0;  // error: no j in B
		using namespace B;
		j = 0;     // fine: B is unlocked
		           // and so is A
	}

July '95, Monterey: qualified name lookup in namespaces has been fixed!


This can get particularly confusing, in my opinion, when functions are involved instead of variables, because they overload across namespaces once any namespace in the chain is unlocked!

	namespace A {
		void h(int);
	}
	namespace B {
		using namespace A;
		void h(char);
	}
	void f()
	{
		A::h('a');  // calls A::h(int)
		B::h(123);  // calls B::h(char)
		using namespace B;
		h('a');     // chooses B::h(char)
		h(123);     // chooses A::h(int)
	}

I'll leave it as an exercise to construct more complicated examples but I'd like to hear your comments on this - send me email about it and I'll summarise in Overload 9. [actually, I didn't revisit this until Overload 10]