Previous Table of Contents Next


3.20.2 Scoping Rules and Name Resolution


   Contents of an entire OMG IDL file, together with the contents of any files referenced by #include statements, forms a naming scope. Definitions that do not appear inside a scope are part of the global scope. There is only a single global scope, irrespective of the number of source files that form a specification.

   The following kinds of definitions form scopes:

   The scope for module, interface, valuetype, struct, exception, eventtype, component, and home begins immediately following its opening ‘{‘ and ends immediately preceding its closing ‘}’. The scope of an operation begins immediately following its ‘(‘ and ends immediately preceding its closing ‘)’. The scope of a union begins immediately following the ‘(‘ following the keyword switch, and ends immediately preceding its closing ‘}’. The appearance of the declaration of any of these kinds in any scope, subject to semantic validity of such declaration, opens a nested scope associated with that declaration.

   An identifier can only be defined once in a scope. However, identifiers can be redefined in nested scopes. An identifier declaring a module is considered to be defined by its first occurrence in a scope. Subsequent occurrences of a module declaration with the same identifier within the same scope reopens the module and hence its scope, allowing additional definitions to be added to it.

   The name of an interface, value type, struct, union, exception, or a module may not be redefined within the immediate scope of the interface, value type, struct, union, exception, or the module. For example:

   module M { typedef short M; // Error: M is the name of the module // in the scope of which the typedef is. interface I { void i (in short j); // Error: i clashes with the interface name I }; };

   An identifier from a surrounding scope is introduced into a scope if it is used in that scope. An identifier is not introduced into a scope by merely being visible in that scope. The use of a scoped name introduces the identifier of the outermost scope of the scoped name. For example in:

   module M { module Inner1 { typedef string S1; };

   module Inner2 { typedef string inner1; // OK }; }

   The declaration of Inner2::inner1 is OK because the identifier Inner1, while visible in module Inner2, has not been introduced into module Inner2 by actual use of it. On the other hand, if module Inner2 were:

   module Inner2{

   typedef Inner1::S1 S2; // Inner1 introduced

   typedef string inner1; // Error

   typedef string S1; // OK };

   The definition of inner1 is now an error because the identifier Inner1 referring to the module Inner1 has been introduced in the scope of module Inner2 in the first line of the module declaration. Also, the declaration of S1 in the last line is OK since the identifier S1 was not introduced into the scope by the use of Inner1::S1 in the first line.

   Only the first identifier in a qualified name is introduced into the current scope. This is illustrated by Inner1::S1 in the example above, which introduces “Inner1? into the scope of “Inner2? but does not introduce “S1.? A qualified name of the form “::X::Y::Z? does not cause “X? to be introduced, but a qualified name of the form “X::Y::Z? does.

   Enumeration value names are introduced into the enclosing scope and then are treated like any other declaration in that scope. For example:

   interface A { enum E { E1, E2, E3 }; // line 1

   enum BadE { E3, E4, E5 }; // Error: E3 is already introduced // into the A scope in line 1 above };

   interface C { enum AnotherE { E1, E2, E3 }; };

   interface D : C, A {

   union U switch ( E ) { case A::E1 : boolean b;// OK. case E2 : long l; // Error: E2 is ambiguous (notwithstanding

   // the switch type specification!!) }; };

   Type names defined in a scope are available for immediate use within that scope. In particular, see Section 3.11.2, “Constructed Types,? on page 3-39 on cycles in type definitions.

   A name can be used in an unqualified form within a particular scope; it will be resolved by successively searching farther out in enclosing scopes, while taking into consideration inheritance relationships among interfaces. For example:

   module M { typedef long ArgType; typedef ArgType AType; // line l1 interface B {

   typedef string ArgType; // line l3 ArgType opb(in AType i); // line l2 }; };

module N {

};

typedef char ArgType; // line l4
interface Y : M::B {
void opy(in ArgType i); // line l5
};

   The following scopes are searched for the declaration of ArgType used on line l5:

   M::B::ArgType is found in step 2 in line l3, and that is the definition that is used in line l5, hence ArgType in line l5 is string. It should be noted that ArgType is not char in line l5. Now if line l3 were removed from the definition of interface M::B then ArgType on line l5 would be char from line l4, which is found in step 3.

   Following analogous search steps for the types used in the operation M::B::opb on line l2, the type of AType used on line l2 is long from the typedef in line l1 and the return type ArgType is string from line l3.