]> git.buserror.net Git - polintos/scott/priv.git/blob - doc/idl/namespace-precedence
Initial checkin from Perforce.
[polintos/scott/priv.git] / doc / idl / namespace-precedence
1 When a non-globally-qualified identifier is used that could
2 potentially refer to more than one symbol in different namespaces,
3 the following rules are used to determine which, if any, is assumed
4 to be the intended symbol:
5
6 The current stack of parent namespaces (not parent types) is
7 searched, starting with the current namespace and proceeding outward. 
8 At each level, the following searches are made in order:
9
10 1. All symbols declared directly in the namespace, including aliases
11 and symbols imported with a specific using statement.
12
13 2. Symbols imported by a using namespace statement at that level.  If
14 more than one imported symbol is matched, it is an error.  Symbols
15 imported by a using statement take effect immediately, and are used
16 for subsequent imports, even in the same statement.  Lookups for any
17 purpose *other* than a using statement use all importations,
18 regardless of whether they come before or after the lookup in the
19 file.
20
21 Symbols defined in namespaces of inherited types are not imported, as
22 I felt that for IDL, the benefit wasn't worth the implementation
23 complexity (there are some chicken-and-egg problems; aliases declared
24 in the namespace need to be looked up early so that alias chains can
25 be formed, but inherited types need to be looked up earlier so that
26 they can be used for namespace searches, but types can be inherited
27 using alias names...).
28
29 Note that importing a namespace does not bring the symbol name of that
30 namespace into the current namespace along with its context.  In
31 certain circumstances, this could lead to problems if the name used
32 to refer to the namespace is shadowed by an imported name.  This
33 won't necessarily cause an error to be reported, if the name that was
34 used for importing the namespace was imported or declared in an outer
35 namespace, and the alternate name is valid in the context used.  In
36 general, you should not use whole-namespace imports except for
37 closely related bits of code/interfaces where you can be sure that
38 nothing unintended is getting imported.
39
40 At some point, I may change this so that imported namespace names
41 (including the path as used to import) do get added as private
42 aliases.  If so, it could apply to inherited types as well.
43
44 If a match is found at one rule, the search stops, and no further
45 rules or levels are considered.  If an error occurs, the search also
46 stops (i.e. a proper match at a later level does not undo the error).
47
48 If no symbols were found in the above steps, the global namespace is
49 searched.
50
51 Only the first component of a namespace-qualified name is looked up;
52 further components are not used for disambiguation.
53
54 Note that when using a namespace either in a namespace statement, or
55 when creating a type using a qualified identifier, no searching is
56 done, but the current namespace is assumed (or global, if there's a
57 leading "..").  If the namespace does not exist, it is created.
58
59 Example:
60
61 namespace A {
62    struct D {
63    };
64    
65    struct F {
66    };
67
68    // A.G is declared as a namespace; no attempt is made to look for
69    // a global G.
70    struct G.Q {
71    };
72 }
73
74 struct B {
75    struct C {
76       struct X {
77       };
78    };
79    
80    struct G {
81    };
82    
83    struct H {
84    };
85
86         struct I {
87         };
88 };
89
90 namespace C {
91    using A.*;
92    
93    struct D {
94    };
95    
96    struct E {
97    };
98    
99    struct F {
100    };
101    
102    struct H {
103    };
104
105         struct I {
106         };
107    
108    struct B.E {
109       struct F {
110       };
111       
112       struct E {
113       };
114       
115       B b;    // Error: Uses C.B, rule #1 once C is reached,
116               // but C.B is not a type
117       D d;    // Uses C.D, rule #1 once C is reached
118       B.E be; // Uses C.B.E, rule #1 once C is reached
119       E e;    // Uses C.B.E.E, rule #1 in current namespace
120       E.E ee; // Error, as the first E matches C.B.E.E, and
121               // there is no C.B.E.E.E.  The extra .E is
122               // not used for disambiguation.
123       F f;    // Uses C.B.E.F, rule #1 in current namespace
124       G g;    // Error, Uses A.G, rule #2 once namespace C is
125               // reached, but A.G is not a type
126       H h;    // Uses C.H, rule #1 once namespace C is reached.
127    };
128 }
129
130 struct D {
131         // Imports B and B.C, not B and C.  If it were "using C.*, B.*",
132         // then it would import C and C.B.
133
134    using B.*, C.*;
135    using ..B.I;
136    
137    struct E {
138       B b;    // Error: Uses C.B, rule #2 once D is reached, but C.B
139               // not a type.  Only the contents of namespaces are
140                         // imported, not the names themselves.
141       C.D cd; // Error.  For the same reason as above, C refers
142               // to B.C, not C.  There is no D in B.C.
143       C.X cx; // Uses B.C.X.
144       D d;    // Uses C.D, rule #2 when D is reached.  D itself
145               // is declared in the global namespace, which doesn't
146               // get reached because a match is found sooner.
147       E e;    // Uses D.E, rule #1 once D is reached.  C.E would 
148               // have been matched by rule #2 if D.E did not exist.
149       F f;    // Uses C.F, rule #2 once D is reached.  A.F is not
150               // matched, as importation is not transitive.
151       G g;    // Uses B.G, rule #2
152       H h;    // Error, both B.H and C.H match on rule #2 once
153               // D is reached.  B does not get precedence for
154               // coming first, or because the C importation
155               // comes after this lookup.
156                 I i;    // Uses B.I, as specific-symbol imports are treated
157                         // as symbols declared in this namespace, rather than
158                         // imports (and thus B.I has precedence over C.I).
159    };
160    
161    int I;     // Error; this conflicts with the specific-symbol
162                    // importation of B.I.
163
164    // Now C is imported.  This importation is valid through the
165    // entire namespace (except for prior using statements), not just
166    // after this point.
167    
168    using ..C.*;
169 };
170
171
172 It goes without saying that it is not recommended that code be
173 written which relies excessively on these rules; they are mainly
174 intended so that:
175
176 1. Local namespaces are not unduly restricted by what some imported
177 library declares, and
178
179 2. If there is an ambiguity, all compilers will handle it the same
180 way.