When a non-globally-qualified identifier is used that could potentially refer to more than one symbol in different namespaces, the following rules are used to determine which, if any, is assumed to be the intended symbol: The current stack of parent namespaces (not parent types) is searched, starting with the current namespace and proceeding outward. At each level, the following searches are made in order: 1. All symbols declared directly in the namespace, including aliases and symbols imported with a specific using statement. 2. Symbols imported by a using namespace statement at that level. If more than one imported symbol is matched, it is an error. Symbols imported by a using statement take effect immediately, and are used for subsequent imports, even in the same statement. Lookups for any purpose *other* than a using statement use all importations, regardless of whether they come before or after the lookup in the file. Symbols defined in namespaces of inherited types are not imported, as I felt that for IDL, the benefit wasn't worth the implementation complexity (there are some chicken-and-egg problems; aliases declared in the namespace need to be looked up early so that alias chains can be formed, but inherited types need to be looked up earlier so that they can be used for namespace searches, but types can be inherited using alias names...). Note that importing a namespace does not bring the symbol name of that namespace into the current namespace along with its context. In certain circumstances, this could lead to problems if the name used to refer to the namespace is shadowed by an imported name. This won't necessarily cause an error to be reported, if the name that was used for importing the namespace was imported or declared in an outer namespace, and the alternate name is valid in the context used. In general, you should not use whole-namespace imports except for closely related bits of code/interfaces where you can be sure that nothing unintended is getting imported. At some point, I may change this so that imported namespace names (including the path as used to import) do get added as private aliases. If so, it could apply to inherited types as well. If a match is found at one rule, the search stops, and no further rules or levels are considered. If an error occurs, the search also stops (i.e. a proper match at a later level does not undo the error). If no symbols were found in the above steps, the global namespace is searched. Only the first component of a namespace-qualified name is looked up; further components are not used for disambiguation. Note that when using a namespace either in a namespace statement, or when creating a type using a qualified identifier, no searching is done, but the current namespace is assumed (or global, if there's a leading ".."). If the namespace does not exist, it is created. Example: namespace A { struct D { }; struct F { }; // A.G is declared as a namespace; no attempt is made to look for // a global G. struct G.Q { }; } struct B { struct C { struct X { }; }; struct G { }; struct H { }; struct I { }; }; namespace C { using A.*; struct D { }; struct E { }; struct F { }; struct H { }; struct I { }; struct B.E { struct F { }; struct E { }; B b; // Error: Uses C.B, rule #1 once C is reached, // but C.B is not a type D d; // Uses C.D, rule #1 once C is reached B.E be; // Uses C.B.E, rule #1 once C is reached E e; // Uses C.B.E.E, rule #1 in current namespace E.E ee; // Error, as the first E matches C.B.E.E, and // there is no C.B.E.E.E. The extra .E is // not used for disambiguation. F f; // Uses C.B.E.F, rule #1 in current namespace G g; // Error, Uses A.G, rule #2 once namespace C is // reached, but A.G is not a type H h; // Uses C.H, rule #1 once namespace C is reached. }; } struct D { // Imports B and B.C, not B and C. If it were "using C.*, B.*", // then it would import C and C.B. using B.*, C.*; using ..B.I; struct E { B b; // Error: Uses C.B, rule #2 once D is reached, but C.B // not a type. Only the contents of namespaces are // imported, not the names themselves. C.D cd; // Error. For the same reason as above, C refers // to B.C, not C. There is no D in B.C. C.X cx; // Uses B.C.X. D d; // Uses C.D, rule #2 when D is reached. D itself // is declared in the global namespace, which doesn't // get reached because a match is found sooner. E e; // Uses D.E, rule #1 once D is reached. C.E would // have been matched by rule #2 if D.E did not exist. F f; // Uses C.F, rule #2 once D is reached. A.F is not // matched, as importation is not transitive. G g; // Uses B.G, rule #2 H h; // Error, both B.H and C.H match on rule #2 once // D is reached. B does not get precedence for // coming first, or because the C importation // comes after this lookup. I i; // Uses B.I, as specific-symbol imports are treated // as symbols declared in this namespace, rather than // imports (and thus B.I has precedence over C.I). }; int I; // Error; this conflicts with the specific-symbol // importation of B.I. // Now C is imported. This importation is valid through the // entire namespace (except for prior using statements), not just // after this point. using ..C.*; }; It goes without saying that it is not recommended that code be written which relies excessively on these rules; they are mainly intended so that: 1. Local namespaces are not unduly restricted by what some imported library declares, and 2. If there is an ambiguity, all compilers will handle it the same way.