Issue 2980: Problem with the "Special scoping" rules in 3.15.3 (orb_revision) Source: Floorboard Software (Mr. Jonathan Biggar, jon(at)floorboard.com) Nature: Uncategorized Issue Severity: Summary: The special scoping rules make it clear that they apply only to identifiers that name a type, however the second IDL example claims that the import of a constant definition (in this case the identifier I) into an interface scope behaves the same way. So which one is it? Do the rules only apply to type identifiers or to all identifiers? Resolution: The changes below provide clarification. Revised Text: The text below is replacement text for page 3-56 and replaces the paragraph beginning with Once a type identifier has been *used* anywhere within the scope... up to (but excluding) the paragraph Note that redefinitinos of a type after use in a module is OK as in the example: Replacement text: The scope of of a type definition extends from the point of definition to the end of its enclosing scope. (Constant and exception definitions are considered type definitions.) A type is *introduced* into a scope by its use in that scope, if the type name is not a fully-qualified type name. For example: typedef short TempType; // Scope of TempType begins here module M { typedef string ArgType; // Scope of ArgType begins here struct S { ::M::ArgType a1; // Nothing introduced here M::ArgType a2; // M introduced here ::TempType temp; // Nothing introduced here }; // Scope of (introduced) M ends here // ... }; // Scope of ArgType ends here // Scope of global TempType ends here (at end of file) The scope of an introduced type name is from the point of introduction to the end of its enclosing scope. However, if a *type* name is *introduced* into a scope that is nested in a non-module scope definition, its *potential* scope extends over all its enclosing scopes out to the enclosing non-module scope. (For types that are defined outside an inon-module scope, the scope and the potential scope are identical.) For example: module M { typedef long ArgType; const long I = 10; typedef short Y; interface A { struct S { struct T { ArgType x[I]; // ArgType and I introduced long y; // a new y is defined, the existing Y // is not used } m; }; typedef string ArgType; // Error: ArgType redefined enum I { I1, I2 }; // Error: I redefined typedef short Y; // OK }; // Potential scope of ArgType and I ends here }; A type may not be redefined within its scope or potential scope, as shown in the preceding example. This rule prevents type names from changing their meaning throughout a non-module scope definition, and ensures that reordering of definitions in the presence of introduced types does not affect the semantics of a specification. Note that, in the following, the definition of M::A::U::I is legal because it is outside the potential scope of the I introduced in the definition of M::A::S::T::ArgType. However, the definition of M::A::I is still illegal because it is within the potential scope of the I introduced in the definition of M::A::S::T::ArgType. module M { typedef long ArgType; const long I = 10; interface A { struct S { struct T { ArgType x[I]; // ArgType and I introduced } m; }; struct U { long I; // OK, I is not a type name }; enum I { I1, I2 }; // Error: I redefined }; // Potential scope of ArgType and I ends here }; Actions taken: November 8, 1999: received issue February 27, 2001: closed issue Discussion: End of Annotations:===== Sender: jon@floorboard.com Message-ID: <3826185C.99E7038E@floorboard.com> Date: Sun, 07 Nov 1999 16:25:00 -0800 From: Jonathan Biggar X-Mailer: Mozilla 4.6 [en] (X11; U; SunOS 5.5.1 sun4m) X-Accept-Language: en MIME-Version: 1.0 To: issues@omg.org, orb_revision@omg.org Subject: Problem with the "Special scoping" rules in 3.15.3 Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-UIDL: 5*Ne9=Nn!!1a~e9X\@!! The special scoping rules make it clear that they apply only to identifiers that name a type, however the second IDL example claims that the import of a constant definition (in this case the identifier I) into an interface scope behaves the same way. So which one is it? Do the rules only apply to type identifiers or to all identifiers? If it only applies to type identifiers, then the comment in the pertenant lines in the example needs to be rewritten as: ... ArgType x[I]; // x is a long[10], ArgType is used ... enum I {I1, I2}; // OK: M::I is not a type ... -- Jon Biggar Floorboard Software jon@floorboard.com jon@biggar.org From: Paul Kyzivat To: "'jon@floorboard.com'" , "'issues@omg.org'" , "'orb_revision@omg.org'" Subject: RE: Problem with the "Special scoping" rules in 3.15.3 Date: Mon, 8 Nov 1999 09:29:24 -0500 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2448.0) Content-Type: text/plain; charset="iso-8859-1" X-UIDL: "):e9\KEe9a~Ie9*`e!! > From: jon@floorboard.com [mailto:jon@floorboard.com] ... > The special scoping rules make it clear that they apply only to > identifiers that name a type, however the second IDL example > claims that > the import of a constant definition (in this case the > identifier I) into > an interface scope behaves the same way. > > So which one is it? Do the rules only apply to type identifiers or to > all identifiers? Seems to me that this should apply to all identifiers. Since identifiers of all kinds can collide and mask one another it makes little sense to have different rules for different kinds. Now that you highlight this section, it seems to me that there other wording violates the least astonishment rule. In particular, I fail to see why use of a type in a struct should be considered a use in a surrounding interface, but not in a surrounding module. Date: Tue, 9 Nov 1999 10:36:36 +1000 (EST) From: Michi Henning X-Sender: michi@bobo.triodia.com To: Jonathan Biggar cc: issues@omg.org, orb_revision@omg.org Subject: Re: Problem with the "Special scoping" rules in 3.15.3 In-Reply-To: <3826185C.99E7038E@floorboard.com> Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: W8,!!%/Zd9*H&!!FPg!! On Sun, 7 Nov 1999, Jonathan Biggar wrote: > The special scoping rules make it clear that they apply only to > identifiers that name a type, however the second IDL example claims > that > the import of a constant definition (in this case the identifier I) > into > an interface scope behaves the same way. > > So which one is it? Do the rules only apply to type identifiers or > to > all identifiers? > > If it only applies to type identifiers, then the comment in the > pertenant lines in the example needs to be rewritten as: > > ... > ArgType x[I]; // x is a long[10], ArgType is used > ... > enum I {I1, I2}; // OK: M::I is not a type The example is correct as written. The problem is with the wording, IMO. The idea of all this was to prevent having an identifier change meaning halfway through an interface declaration. Whether that happens through a constant or a type name should be irrelevant. Cheers, Michi. -- Michi Henning +61 7 3236 1633 Object Oriented Concepts +61 4 1118 2700 (mobile) PO Box 372 +61 7 3211 0047 (fax) Annerley 4103 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html Date: Tue, 9 Nov 1999 12:44:07 +1000 (EST) From: Michi Henning X-Sender: michi@bobo.triodia.com To: Paul Kyzivat cc: "'jon@floorboard.com'" , "'orb_revision@omg.org'" Subject: RE: Problem with the "Special scoping" rules in 3.15.3 In-Reply-To: <9B164B713EE9D211B6DC0090273CEEA91401B3@bos1.noblenet.com> Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: :'nd9Nfa!!):l!!LVIe9 On Mon, 8 Nov 1999, Paul Kyzivat wrote: > Now that you highlight this section, it seems to me that there other wording > violates the least astonishment rule. In particular, I fail to see why use > of a type in a struct should be considered a use in a surrounding interface, > but not in a surrounding module. Paul, below is an e-mail I wrote when we made these changes initially, about 18 months ago. I think that one explains the rationale for the current rules (which still strike me as correct). The only proplem we have is that redefinition of a constant is permitted, but not forbidden if it changes meaning halfway through a scope. I would suggest to extend the prohibition to constants, as suggested by Jon: const long l = 1; interface I { typedef x[l]; const long l = 5; // Currently legal }; That one should be made illegal because the meaning of the name "l" changes halfway through the scope of I. Now, back to the scoping rules for modules and interfaces. Below is the original message. Cheers, Michi. I think the text is very close. I looked to the ANSI C++ spec for inspiration. It says in section 3.3.6 ("Class scope"): The following rules describe the scope of names declared in classes. 1) The potential scope of a name declared in a class consists not only of the declarative region following the name's declarator, but also of all function bodies, default arguments, and constructor ctor-initializers in that class (including such things in nested classes). 2) A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the complete scope of S. No diagnostic is required for a violation of this rule. 3) If reordering member declarations in a class yields an alternate valid program under (1) and (2), the program's behavior is ill-formed, no diagnostic is required. 4) A name declared within a member fucntion hides a declaration of the same name whose scope extends to or past the end of the member function's class. 5) The potential scope of a declaration that extends to or past the end of a class defintion also extends to the regions defined by its member definitions, even if the members are defined lexically outside the class (this includes static data member definitions, nested class definitions, member function definitions (including the member function body and, for constructor functions (12.1), the ctor-initializer (12.6.2)) and any portion of the declaraator part of such defintions which follows the identifier, including a parameter-declaration-clause and any default arguments (8.3.6). [ Example: typedef int c; enum { i = 1 }; class X { char v[i]; // error: 'i' refers to ::i // but when reevaluated is X::i int f() { return sizeof(c); } // okay: X::c char c; enum { i = 2 }; }; typedef char* T; struct Y { T a; // error: 'T' refers to ::T // but when reevaluated is Y::T typedef long T; T b; }; - end example] This captures it quite well. Some points, such (4) don't apply to IDL, but pretty much a straight translation into IDL terminology would do I think. The interesting bit is that the following is illegal: typedef char* T; struct Y { T a; // error: 'T' refers to ::T // but when reevaluated is Y::T typedef long T; T b; }; We all seem to agree on that. However, apparently C++ allows re-definition of a used type if the enclosing scope is a *namespace* instead of a class: typedef char* T; namespace Y { T a; // a is a char * typedef long T; // OK T b; // OK, b is a long }; At least, I can't find a rule in the spec which would state that this is illegal, and my trusty HP aCC compiler compiles this without complaint. However, C++ still makes redefinition of the same type in the same scope illegal: typedef char* T; namespace Y { T a; // a is a char * typedef long T; // OK T b; // OK, b is a long typedef short T;// Illegal, redefinition in the same scope }; For complete consistency with C++, we would have to disallow redefinition of a used type within interface scope, but permit redefinition of a used type in a module, if the used type is defined in one of the module's enclosing scopes (but I don't like this). Everyone properly confused now? ;-) I think that C++ did it this way to ensure sanity for virtual functions and overloading. That's why the redefinition rules for classes are more strict than for namespaces. Also, the more relaxed rules are necessary for namespaces because I may want to import someone else's namespace like this: namespace MyNameSpace { #include "SomeOtherNamespace" // Assume this defines ArgType typedef long ArgType; // I don't want this to break // because of what goes on in // SomeOtherNamespace ArgType foo(); // foo() returns a long } From: "Dan Frantz" To: Subject: RE: Problem with the "Special scoping" rules in 3.15.3 Date: Tue, 9 Nov 1999 10:27:27 -0500 Message-ID: <000201bf2ac6$eeef3ad0$3fc5bdce@beasys.com> MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook CWS, Build 9.0.2416 (9.0.2910.0) In-Reply-To: X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2314.1300 Importance: Normal Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset="us-ascii" X-UIDL: Teh!!ELBe9+U8!!i(Sd9 >-----Original Message----- >From: Michi Henning [mailto:michi@ooc.com.au] >Sent: Monday, November 08, 1999 21:44 ... >The only proplem we have is that redefinition of a constant is >permitted, but not forbidden if it changes meaning halfway >through a scope. I would suggest to extend the prohibition to >constants, as suggested by Jon: > > const long l = 1; > interface I { > typedef x[l]; > const long l = 5; // Currently legal > }; > >That one should be made illegal because the meaning of the >name "l" changes halfway through the scope of I. If we make the prohibition for constants for consistency, we really should do it for exceptions as well. Consider: exception Q{long a;} interface B { void op1() raises (Q); exception Q{short s;} void op2() raises (Q); }; Dan From: Paul Kyzivat To: "'Michi Henning'" , Paul Kyzivat Cc: "'jon@floorboard.com'" , "'orb_revision@omg.org'" Subject: RE: Problem with the "Special scoping" rules in 3.15.3 Date: Tue, 9 Nov 1999 10:55:50 -0500 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2448.0) Content-Type: text/plain; charset="iso-8859-1" X-UIDL: $8>!!nie!!XaQ!!bZ$e9 > From: Michi Henning [mailto:michi@ooc.com.au] ... > > Now that you highlight this section, it seems to me that > > there other wording violates the least astonishment rule. > > In particular, I fail to see why use > > of a type in a struct should be considered a use in a > > surrounding interface, but not in a surrounding module. ... > The interesting bit is that the following is illegal: > > typedef char* T; > struct Y { > T a; // error: 'T' refers to ::T > // but when reevaluated is Y::T > typedef long T; > T b; > }; I don't have any problem with this. But I think the translation to corba became a bit more extreme. In particular, I think the following is legal in c++: class A { struct B { typedef long T; T x; }; typedef char T; T y(); }; but comparable idl is illegal: interface A { struct B { typedef long T; T x; }; typedef char T; T y(); }; > > We all seem to agree on that. However, apparently C++ allows > re-definition of a used type if the enclosing scope is a *namespace* > instead of a class: > > typedef char* T; > namespace Y { > T a; // a is a char * > typedef long T; // OK > T b; // OK, b is a long > }; > > At least, I can't find a rule in the spec which would state > that this is illegal, and my trusty HP aCC compiler compiles > this without complaint. Well, if aCC (the pickiest of the picky) compiles it then it must be ok :-) But unlike most of the rules, I can't see any rationale for this being legal. > I think that C++ did it this way to ensure sanity for virtual > functions and overloading. That's why the redefinition rules > for classes > are more strict than for namespaces. Also, the more relaxed rules > are necessary for namespaces because I may want to import > someone else's namespace like this: > > namespace MyNameSpace { > #include "SomeOtherNamespace" // Assume this defines ArgType > > > typedef long ArgType; // I don't want this to break > // because of what goes on in > // SomeOtherNamespace > > ArgType foo(); // foo() returns a long > } as long as "SomeOtherNamespace" includes text that begins with "namespace SomeOtherNamespace{" and ends with "}" there is no problem with another definition of ArgType within it. The whole point of namespaces (or modules) is to define distinct name scopes. Having multiple definitions of the same name within the same namespace (other than via overloading) makes no sense. Date: Wed, 10 Nov 1999 06:08:52 +1000 (EST) From: Michi Henning X-Sender: michi@bobo.triodia.com To: Paul Kyzivat cc: "'jon@floorboard.com'" , "'orb_revision@omg.org'" Subject: RE: Problem with the "Special scoping" rules in 3.15.3 In-Reply-To: <9B164B713EE9D211B6DC0090273CEEA91401BE@bos1.noblenet.com> Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: IWQ!!24fd9!(A!!<9l!! On Tue, 9 Nov 1999, Paul Kyzivat wrote: > I don't have any problem with this. But I think the translation to corba > became a bit more extreme. In particular, I think the following is legal in > c++: > > class A { > struct B { > typedef long T; > T x; > }; > typedef char T; > T y(); > }; No Paul, that is not legal C++. > > I think that C++ did it this way to ensure sanity for virtual > > functions and overloading. That's why the redefinition rules > > for classes > > are more strict than for namespaces. Also, the more relaxed rules > > are necessary for namespaces because I may want to import > > someone else's namespace like this: > > > > namespace MyNameSpace { > > #include "SomeOtherNamespace" // Assume this defines ArgType > > > > > > typedef long ArgType; // I don't want this to break > > // because of what goes on in > > // SomeOtherNamespace > > > > ArgType foo(); // foo() returns a long > > } > > as long as "SomeOtherNamespace" includes text that begins with > "namespace > SomeOtherNamespace{" and ends with "}" there is no problem with > another > definition of ArgType within it. > > The whole point of namespaces (or modules) is to define distinct > name > scopes. Having multiple definitions of the same name within the same > namespace (other than via overloading) makes no sense. See the rational above. Namespaces have different rules because you don't want a change in an included namespace to affect what follows the inclusion. Classes need tighter sanity checks to avoid surprises in the types of member functionas and methods. At any rate, I'm convinced that the present rules with respect to this are OK and don't need changing, apart from Jon's const issue. Cheers, Michi. -- Michi Henning +61 7 3236 1633 Object Oriented Concepts +61 4 1118 2700 (mobile) PO Box 372 +61 7 3211 0047 (fax) Annerley 4103 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html Date: Wed, 10 Nov 1999 07:24:03 +1000 (EST) From: Michi Henning X-Sender: michi@bobo.triodia.com To: Jonathan Biggar cc: Paul Kyzivat , "'orb_revision@omg.org'" Subject: Re: Problem with the "Special scoping" rules in 3.15.3 In-Reply-To: <38288C7A.87E852EE@floorboard.com> Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: p2cd9fBIe9*fR!!+1c!! On Tue, 9 Nov 1999, Jonathan Biggar wrote: > > At any rate, I'm convinced that the present rules with respect to this > > are OK and don't need changing, apart from Jon's const issue. > > And whoever-it-was's exception issue. :-) I think whoever-it-was's official name is "Dan Lurker" :-) Cheers, Michi. -- Michi Henning +61 7 3236 1633 Object Oriented Concepts +61 4 1118 2700 (mobile) PO Box 372 +61 7 3211 0047 (fax) Annerley 4103 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html Sender: jon@floorboard.com Message-ID: <38288C7A.87E852EE@floorboard.com> Date: Tue, 09 Nov 1999 13:04:58 -0800 From: Jonathan Biggar X-Mailer: Mozilla 4.6 [en] (X11; U; SunOS 5.5.1 sun4m) X-Accept-Language: en MIME-Version: 1.0 To: Michi Henning CC: Paul Kyzivat , "'orb_revision@omg.org'" Subject: Re: Problem with the "Special scoping" rules in 3.15.3 References: Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-UIDL: (+4!!#5Ee9#0e!!](?!! Michi Henning wrote: > See the rational above. Namespaces have different rules because you > don't > want a change in an included namespace to affect what follows the > inclusion. Classes need tighter sanity checks to avoid surprises in > the > types of member functionas and methods. > > At any rate, I'm convinced that the present rules with respect to > this > are OK and don't need changing, apart from Jon's const issue. And whoever-it-was's exception issue. :-) -- Jon Biggar Floorboard Software jon@floorboard.com jon@biggar.org Date: Wed, 10 Nov 1999 06:58:55 +1000 (EST) From: Michi Henning X-Sender: michi@bobo.triodia.com To: Dan Frantz cc: orb_revision@omg.org Subject: RE: Problem with the "Special scoping" rules in 3.15.3 In-Reply-To: <000201bf2ac6$eeef3ad0$3fc5bdce@beasys.com> Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: Ic2e979Od9n9fd92T]!! On Tue, 9 Nov 1999, Dan Frantz wrote: > If we make the prohibition for constants for consistency, we really > should do it for exceptions as well. Consider: > > exception Q{long a;} > interface B { > void op1() raises (Q); > exception Q{short s;} > void op2() raises (Q); > }; Dan is 100% correct, of course. Cheers, Michi. -- Michi Henning +61 7 3236 1633 Object Oriented Concepts +61 4 1118 2700 (mobile) PO Box 372 +61 7 3211 0047 (fax) Annerley 4103 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html From: Paul Kyzivat To: "'Michi Henning'" , Paul Kyzivat Cc: "'jon@floorboard.com'" , "'orb_revision@omg.org'" Subject: RE: Problem with the "Special scoping" rules in 3.15.3 Date: Tue, 9 Nov 1999 18:17:02 -0500 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2448.0) Content-Type: text/plain; charset="iso-8859-1" X-UIDL: m4"!!G/od9@`He9?ZU!! > From: Michi Henning [mailto:michi@ooc.com.au] ... > On Tue, 9 Nov 1999, Paul Kyzivat wrote: > > > > class A { > > struct B { > > typedef long T; > > T x; > > }; > > typedef char T; > > T y(); > > }; > > No Paul, that is not legal C++. Well, please explain to me why it is wrong, and why both msvc and aCC compile it. After some thinking, I may finally get the point you are trying to make, but it isn't covered by the text or examples so far. The following is illegal C++: typedef bool T; struct A { struct B { T x; // this imports the def of T into both A and B }; typedef long T; // this is illegal because of the above import }; It is the use of something declared in an outer scope that *imports* it into all the scopes between the point of definition and the point of use. It does not *export* something defined in the inner scope to enclosing outer scopes. And, without going back to the spec to be sure, I think you are right that it does not import into intervening namespace scopes. But the words in section 3 have the effect of exporting something from an inner scope to an outer scope. This is what I am objecting to. Translating all this into idl, here are some cases: module M1 { struct S { typedef long T; T x; }; typedef float T; // legal T y; }; module M2 { typedef long T; struct S1 { struct S2 { T x; // this imports the def of T into S1 & S2 }; typedef float T; // illegal T y; }; }; module M2 { typedef long T; module M3 { struct S3 { T x; // this imports the def of T into S3 but not M3 }; typedef float T; // legal T y; }; }; Date: Wed, 10 Nov 1999 11:53:41 +1000 (EST) From: Michi Henning X-Sender: michi@bobo.triodia.com To: Paul Kyzivat cc: "'jon@floorboard.com'" , "'orb_revision@omg.org'" Subject: RE: Problem with the "Special scoping" rules in 3.15.3 In-Reply-To: <9B164B713EE9D211B6DC0090273CEEA91401C5@bos1.noblenet.com> Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: FYGe9Kc&!!6a5!!=C/e9 On Tue, 9 Nov 1999, Paul Kyzivat wrote: > > > class A { > > > struct B { > > > typedef long T; > > > T x; > > > }; > > > typedef char T; > > > T y(); > > > }; > > > > No Paul, that is not legal C++. > > Well, please explain to me why it is wrong, and why both msvc and > aCC > compile it. Oops, my apologies. I jumped the gun and assumed that the example you posted was the same as the one on page 3-50. Serves me right, I should have checked. You are correct, the above is legal C++. However, the following is not legal: typedef long T; struct A { struct S { T x; }; typedef char * T; }; Here is why: in the first example, struct B defines its own type T and uses it. The potential scope of B::T extends to the end of B. After that, T is no longer visible to the name resolution rules (except by explicit qualification). In the second example, the potential scope of T extends over the entire example. S::x uses the global T. The attempt to define A::T then becomes illegal because it would mean that, within the scope of A, there would be two types T with different meaning. However, if S defines its own T, things are fine again: typedef long T; struct A { struct S { typedef short T; T x; // x is short, OK }; typedef char * T; // T is char *, OK }; > After some thinking, I may finally get the point you are trying to make, but > it isn't covered by the text or examples so far. > > The following is illegal C++: > > typedef bool T; > struct A { > struct B { > T x; // this imports the def of T into both A and B > }; > typedef long T; // this is illegal because of the above import > }; Isn't that the same as the last example on page 3-50? > It is the use of something declared in an outer scope that *imports* it into > all the scopes between the point of definition and the point of use. It does > not *export* something defined in the inner scope to enclosing outer scopes. Yes. The C++ spec defines this in terms of "potential scope". > And, without going back to the spec to be sure, I think you are right that > it does not import into intervening namespace scopes. That's my understanding, and experimenting with aCC confirms this. > But the words in section 3 have the effect of exporting something from an > inner scope to an outer scope. This is what I am objecting to. I think you are right. The term "used" in the para between the two examples on page 3-50 is too loose. I suspect that we need a more formal definition along the lines of the C++ spec, which defines potential scope and under what circumstances redefinitions are illegal. > Translating all this into idl, here are some cases: > > module M1 { > struct S { > typedef long T; > T x; > }; > typedef float T; // legal > T y; > }; Yes. > module M2 { > typedef long T; > struct S1 { > struct S2 { > T x; // this imports the def of T into S1 & S2 > }; > typedef float T; // illegal > T y; > }; > }; Yes. > module M2 { > typedef long T; > module M3 { > struct S3 { > T x; // this imports the def of T into S3 but not M3 > }; > typedef float T; // legal > T y; > }; > }; Yes. Hey, we are agreeing *again*! :-) Cheers, Michi. -- Michi Henning +61 7 3236 1633 Object Oriented Concepts +61 4 1118 2700 (mobile) PO Box 372 +61 7 3211 0047 (fax) Annerley 4103 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html Date: Thu, 30 Mar 2000 17:27:24 +1000 (EST) From: Michi Henning Reply-To: Core Revision Task Force To: Core Revision Task Force Subject: Proposal for 2980 Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: ,,_d9om*!!gk*!!Xi@!! Here is the proposal for 2980. I stared this and thought about it for a long time. I think I've found the correct answer, but it will need careful review. This has turned into a rather long message because I wanted to explain what is going on and the motivation for arriving at this proposal. Please bear with me -- I think it's important that we get this right. To explain what's really going on, consider the following bit of C++: typedef long ArgType; struct M { struct S { ArgType x; // x is a long }; typedef char * ArgType; // Illegal! struct T { ArgType y; // y would be a char * }; }; This is illegal C++. There are good reasons for why this should be illegal. Basically, the whole idea is that the meaning of an identifier must not change throughout a scope. By enforcing that rule, it is guaranteed that reordering of definitions in a scope does not yield a program with different meaning. For example, the above code would have completely different meaning if the definition of M::ArgType were placed before the definition of M::S: typedef long ArgType; struct M { typedef char * ArgType; struct S { ArgType x; // x is a char * }; struct T { ArgType y; // y is a char * }; }; If we add another typedef to the first example, it becomes legal: typedef long ArgType; struct M { struct S { typedef short ArgType; ArgType x; // x is a short }; typedef char * ArgType; // OK struct T { ArgType y; // y is a char * }; }; The motivation for this is to avoid getting trapped by things that don't use a qualifed name and that I am therefore importing into the current scope via the scope resolution rules. By defining S::ArgType, no implicit import of the meaning of an identifier happens, so there is no problem with an identifier changing its meaning. As a consequence, reordering of the definitions now yields the same types: typedef long ArgType; struct M { typedef char * ArgType; struct S { typedef short ArgType; ArgType x; // x is a short }; struct T { ArgType y; // y is a char * }; }; Now, let's go back to the very first example once more. What follows is exactly the same example, but I have changed struct M to namespace M: typedef long ArgType; namespace M { struct S { ArgType x; // x is a long }; typedef char * ArgType; // OK struct T { ArgType y; // y is a char * }; } So, for structs (i.e. classes), C++ applies different rules than for namespaces. Again, there are good reasons for this. For example, I don't want to get trapped by something like this: namespace M { #include "namespace_N" // namespace N defines N::ArgType typedef long ArgType; // This must be allowed ArgType x; // x is a long } In other words, the rules for namespaces are more relaxed because reordering of definitions does not matter to C++ here (because no issues arise from things like inconsistent type interpretation by member functions). Now, when we beefed up the scope resolution rules for IDL, we decided that we should follow the C++ model. That was because it ensures that IDL translates cleanly into C++ and doesn't cause surprises when mapped, and because the C++ committee spent an awful lot more time thinking about these issues than we did (so there is a good chance that they got it right). The problem we have now is that IDL is not C++ (but must be translatable into C++ without major contortions), and that we need to find something that works for IDL without undue restrictions, works for C++, and works for other languages. Because C++ has pretty much the strictest and most consistent typing model I've ever come across, I believe that by using the C++ rules, we are highly unlikely to get problems with other languages (which are more lenient, if anything). So, the rationale for sticking with the C++ model seems sound to me. What follows is a proposal to bring IDL into line with these rules. Before I go into the details, there is one important consequence of adopting this: for compilers that map namespaces to classes, some legal IDL becomes non-mappable. This happens because C++ has more relaxed rules for namespaces, so, if namespaces are mapped to classes, it is possible that there is no legal mapping if the IDL contains a redefinition such as the one I showed for the namespace example. Personally, I do not believe that we should let this concern stop the proposal. Rationale: - Only fairly ugly IDL gets bitten by this. For the problem to show up, the IDL must implicitly import a type name from a surrounding scope and, in addition, redefine the same name to mean something different. Most people would argue that such IDL is very rare and, if it does occur, uses poor style (and can easily be fixed to do better). - If names are explicitly defined (instead of being imported implicitly), no redefinition error ever occurs. In other words, good style avoids the problem. - Standard C++ compilers are getting far more prevalent now, to the point where the mapping from modules to classes is rapidly becoming obsolete. (For example, the latest generation of POA ORBs from various vendors require namespace support in the C++ compiler.) It follows that IDL that cannot be mapped on compilers without namespace support won't upset anyone. - The alternative (using the stricter rules for modules as well) is very unpleasant indeed because it would defeat the purpose of modules (namely, to shield developers from accidental name clashes). So, here is the proposal. The text below is replacement text for page 3-56 and replaces the paragraph beginning with Once a type identifier has been *used* anywhere within the scope... up to (but excluding) the paragraph Note that redefinitinos of a type after use in a module is OK as in the example: Replacement text: The scope of of a type definition extends from the point of definition to the end of its enclosing scope. (Constant and exception definitions are considered type definitions.) A type is *introduced* into a scope by its use in that scope, if the type name is not a fully-qualified type name. For example: typedef short TempType; // Scope of TempType begins here module M { typedef string ArgType; // Scope of ArgType begins here struct S { ::M::ArgType a1; // Nothing introduced here M::ArgType a2; // M introduced here ::TempType temp; // Nothing introduced here }; // Scope of (introduced) M ends here // ... }; // Scope of ArgType ends here // Scope of global TempType ends here (at end of file) The *potential* scope of an *introduced* type name is from the point of introduction to the end of its enclosing scope. (For types that are defined outside an interface or valuetype, the scope and the potential scope are identical.) However, if a type name is *introduced* into a scope that is nested in an interface or valuetype definition, its *potential* scope extends over the entire enclosing scope and all scopes nested within that scope. For example: module M { typedef long ArgType; const long I = 10; typedef short Y; interface A { struct S { struct T { ArgType x[I]; // ArgType and I introduced long y; // a new y is defined, the existing Y // is not used } m; }; typedef string ArgType; // Error: ArgType redefined enum I { I1, I2 }; // Error: I redefined typedef short Y; // OK }; // Potential scope of ArgType and I ends here }; A type may not be redefined within its scope or potential scope, as shown in the preceding example. This rule prevents type names from changing their meaning throughout an interface or valuetype definition, and it ensures that reordering of definitions in the presence of introduced types does not affect the semantics of a specification. Cheers, Michi. From: Paul Kyzivat To: "'Core Revision Task Force'" Subject: RE: Proposal for 2980 Date: Thu, 30 Mar 2000 15:41:45 -0500 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2448.0) Content-Type: text/plain; charset="iso-8859-1" X-UIDL: hoW!!jj'!!+!Ce9V^O!! Michi, A question for you - consider the following variation on your example: module M { typedef long ArgType; const long I = 10; typedef short Y; interface A { struct S { struct T { ArgType x[I]; // ArgType and I introduced long y; // a new y is defined, the existing Y // is not used } m; }; struct U { long I; // Error? Shouldn't be! }; typedef string ArgType; // Error: ArgType redefined enum I { I1, I2 }; // Error: I redefined typedef short Y; // OK }; // Potential scope of ArgType and I ends here }; The difference is the introduction of struct U. If I understand what you are intending, the use of I inside of U should be illegal. But this doesn't make sense to me, and I don't think the comparable usage is illegal in C++. (I haven't tried it, and I don't know that I would trust any particular C++ compiler on this anyway.) Sender: jbiggar@corvette.floorboard.com Message-ID: <38E3CC11.E991B72A@floorboard.com> Date: Thu, 30 Mar 2000 13:50:09 -0800 From: Jonathan Biggar X-Mailer: Mozilla 4.7 [en] (X11; U; SunOS 5.6 sun4u) X-Accept-Language: en MIME-Version: 1.0 To: Paul Kyzivat CC: "'Core Revision Task Force'" Subject: Re: Proposal for 2980 References: <9B164B713EE9D211B6DC0090273CEEA926BD86@bos1.noblenet.com> Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-UIDL: &nRd9p0Td9@JL!!S"=e9 Paul Kyzivat wrote: > > Michi, > > A question for you - consider the following variation on your > example: > > module M { > typedef long ArgType; > const long I = 10; > typedef short Y; > > interface A { > struct S { > struct T { > ArgType x[I]; // ArgType and I introduced > long y; // a new y is defined, the > existing Y > // is not used > } m; > }; > struct U { > long I; // Error? Shouldn't be! > }; > typedef string ArgType; // Error: ArgType redefined > enum I { I1, I2 }; // Error: I redefined > typedef short Y; // OK > }; // Potential scope of ArgType and I ends here > }; > > The difference is the introduction of struct U. > If I understand what you are intending, the use of I inside of U > should be illegal. But this doesn't make sense to me, and I > don't think the comparable usage is illegal in C++. > (I haven't tried it, and I don't know that I would trust any > particular C++ compiler on this anyway.) I agree with Paul. In his example, the declaration of M::A::U::I should be legal. [Besides, I'd rather be in M::A::U::I anyday. :-)] I thought I'd look this up in the C++ standard again, and I'm now totally confused. They have an example (in 3.3.6): typedef int c; enum { i = 1 }; class X { char v[i]; // error: i refers to ::i // but when reevaluated is X::i int f() { return sizeof(c); } // OK: X::c char c; enum { i = 2 }; }; For the life of me, I can't figure out why the use of 'i' is an error, but the use of 'c' is not! -- Jon Biggar Floorboard Software jon@floorboard.com jon@biggar.org Date: Fri, 31 Mar 2000 14:46:21 +1000 (EST) From: Michi Henning To: Paul Kyzivat cc: "'Core Revision Task Force'" Subject: RE: Proposal for 2980 In-Reply-To: <9B164B713EE9D211B6DC0090273CEEA926BD86@bos1.noblenet.com> Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: )6n!!\J,e9pd=!!mL$!! On Thu, 30 Mar 2000, Paul Kyzivat wrote: > Michi, > > A question for you - consider the following variation on your > example: > > > module M { > typedef long ArgType; > const long I = 10; > typedef short Y; > > interface A { > struct S { > struct T { > ArgType x[I]; // ArgType and I introduced > long y; // a new y is defined, the > existing Y > // is not used > } m; > }; > struct U { > long I; // Error? Shouldn't be! > }; > typedef string ArgType; // Error: ArgType redefined > enum I { I1, I2 }; // Error: I redefined > typedef short Y; // OK > }; // Potential scope of ArgType and I ends here > }; > > The difference is the introduction of struct U. > If I understand what you are intending, the use of I inside of U > should be illegal. Yes. > But this doesn't make sense to me, and I > don't think the comparable usage is illegal in C++. > (I haven't tried it, and I don't know that I would trust any > particular C++ compiler on this anyway.) No, that's illegal C++. The relevant words appear in section 3.3.6 of the C++ spec: 3.3.6 Class scope The following rules describe the scope of names declared in classes. 1) The potential scope of a name declared in a class consists not only of the declarative region following the name's declarator, but also of all function bodies, default arguments, and constructor ctor-initializers in that class (including such things in nested classes). 2) A name N used in a class S shall refer to the same declaration in its context and when re-evaluated in the completed scope of S. No diagnostic is required for a violation of this rule. 3) If reordering member declarations in a class yields an alternate valid program under (1) and (2), the pro-gram is ill-formed, no diagnostic is required. 4) A name declared within a member function hides a declaration of the same name whose scope extends to or past the end of the member function's class. 5) The potential scope of a declaration that extends to or past the end of a class definition also extends to the regions defined by its member definitions, even if the members are defined lexically outside the class (this includes static data member definitions, nested class definitions, member function definitions (including the member function body and, for constructor functions (12.1), the ctor-initializer (12.6.2)) and any portion of the declarator part of such definitions which follows the identifier, including a parameter-declaration-clause and any default arguments (8.3.6). What makes your example illegal is rule 2. Consider the definition of U: module M { const long I = 10; interface A { struct S { // ... }; struct U { // Point 1 long I; // Error? Shouldn't be! // Point 2 }; // ... }; }; At point 1, the identifier I resolves to M::I, whereas at point 2, it resolves to U::I. So, the identifier has changed meaning within the scope of U and therefore the definition is ill-formed. Cheers, Michi. -- Michi Henning +61 7 3891 5744 Object Oriented Concepts +61 4 1118 2700 (mobile) Suite 4, 904 Stanley St +61 7 3891 5009 (fax) East Brisbane 4169 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html Date: Fri, 31 Mar 2000 14:47:01 +1000 (EST) From: Michi Henning To: Paul Kyzivat cc: "'Core Revision Task Force'" Subject: RE: Proposal for 2980 In-Reply-To: <9B164B713EE9D211B6DC0090273CEEA926BD86@bos1.noblenet.com> Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: \`jd991 A question for you - consider the following variation on your example: Oops, forgot: aCC correctly diagnoses this. Cheers, Michi. -- Michi Henning +61 7 3891 5744 Object Oriented Concepts +61 4 1118 2700 (mobile) Suite 4, 904 Stanley St +61 7 3891 5009 (fax) East Brisbane 4169 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html Date: Fri, 31 Mar 2000 15:27:20 +1000 (EST) From: Michi Henning To: Jonathan Biggar cc: Paul Kyzivat , "'Core Revision Task Force'" Subject: Re: Proposal for 2980 In-Reply-To: <38E3CC11.E991B72A@floorboard.com> Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: B$X!!#[dd9SChd9@#Pe9 On Thu, 30 Mar 2000, Jonathan Biggar wrote: > I agree with Paul. In his example, the declaration of M::A::U::I should > be legal. Nope, it's not. See section 3.3.6 of the C++ spec. > [Besides, I'd rather be in M::A::U::I anyday. :-)] You can't, at least not without stooping to undefined behavior ;-) > I thought I'd look this up in the C++ standard again, and I'm now > totally confused. They have an example (in 3.3.6): > > typedef int c; > enum { i = 1 }; > class X { > char v[i]; // error: i refers to > ::i > // but when reevaluated is > X::i > int f() { return sizeof(c); } // OK: X::c > char c; > enum { i = 2 }; > }; > > For the life of me, I can't figure out why the use of 'i' is an > error, > but the use of 'c' is not! That one is a bit subtle. Because c is a class member, it is always resolved to X::c inside the body of f(). In other words, reordering things as follows does *not* change the meaning of the program and f() returns 1 regardless: typedef int c; enum { i = 1 }; class X { char v[i]; // error: i refers to ::i // but when reevaluated is X::i char c; int f() { return sizeof(c); } // OK: X::c enum { i = 2 }; }; It has to be that way because the fact that f() is inlined is only coincidental. If you were to outline f(), you wouldn't want to end up with a program that has changed meaning. That's why, when resolved from inside a member function body, names always resolve to the corresponding class members, even if that class member is defined following the definition of the member function (whether inlined or not). The crucial point is that, for this particular example, sizeof(c) is not evaluated in the scope of X, but in the scope of f() (and for lookup from within a function body, different rules apply). However, you can easily make something that's illegal. For example: typedef int c; class X { char v[sizeof(c)]; // error: c refers to ::c // but when reevaluated is X::c char c; }; That's illegal now because sizeof(c), when reevaluated in the scope of X, has a different value and the reordering results in a different program. Cheers, Michi. -- Michi Henning +61 7 3891 5744 Object Oriented Concepts +61 4 1118 2700 (mobile) Suite 4, 904 Stanley St +61 7 3891 5009 (fax) East Brisbane 4169 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html Sender: jon@corvette.floorboard.com Message-ID: <38E438B7.80D584D7@floorboard.com> Date: Thu, 30 Mar 2000 21:33:43 -0800 From: Jonathan Biggar X-Mailer: Mozilla 4.7 [en] (X11; U; SunOS 5.5.1 sun4m) X-Accept-Language: en MIME-Version: 1.0 To: Michi Henning CC: Paul Kyzivat , "'Core Revision Task Force'" Subject: Re: Proposal for 2980 References: Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-UIDL: SLQ!!AU6!!0IJ!!Yg&e9 Michi Henning wrote: > What makes your example illegal is rule 2. Consider the definition > of U: > > module M { > const long I = 10; > > interface A { > struct S { > // ... > }; > struct U { > // Point 1 > long I; // Error? Shouldn't be! > // Point 2 > }; > // ... > }; > }; > > At point 1, the identifier I resolves to M::I, whereas at point 2, > it > resolves to U::I. So, the identifier has changed meaning within the > scope > of U and therefore the definition is ill-formed. I don't agree with you or aCC. :-) Rule 2 requires that the name be used. At point 1, it has not been used in either A or U, so rule 2 should not apply. -- Jon Biggar Floorboard Software jon@floorboard.com jon@biggar.org Sender: jon@corvette.floorboard.com Message-ID: <38E437FC.9874BE5C@floorboard.com> Date: Thu, 30 Mar 2000 21:30:36 -0800 From: Jonathan Biggar X-Mailer: Mozilla 4.7 [en] (X11; U; SunOS 5.5.1 sun4m) X-Accept-Language: en MIME-Version: 1.0 To: Michi Henning CC: Paul Kyzivat , "'Core Revision Task Force'" Subject: Re: Proposal for 2980 References: Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-UIDL: %\D!!+0&!!%n\!!nhn!! Michi Henning wrote: > > I thought I'd look this up in the C++ standard again, and I'm now > > totally confused. They have an example (in 3.3.6): > > > > typedef int c; > > enum { i = 1 }; > > class X { > > char v[i]; // error: i refers > to ::i > > // but when reevaluated is > X::i > > int f() { return sizeof(c); } // OK: X::c > > char c; > > enum { i = 2 }; > > }; > > > > For the life of me, I can't figure out why the use of 'i' is an > error, > > but the use of 'c' is not! > > That one is a bit subtle. Because c is a class member, it is always > resolved to X::c inside the body of f(). In other words, reordering > things > as follows does *not* change the meaning of the program and f() > returns 1 > regardless: Right, I knew that rule and forgot it. -- Jon Biggar Floorboard Software jon@floorboard.com jon@biggar.org From: Paul Kyzivat To: "'Core Revision Task Force'" Subject: RE: Proposal for 2980 Date: Fri, 31 Mar 2000 08:58:26 -0500 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2448.0) Content-Type: text/plain; charset="iso-8859-1" X-UIDL: kNA!!PnBe9%iQ!!SYdd9 > -----Original Message----- > From: Michi Henning [mailto:michi@ooc.com.au] > 2) A name N used in a class S shall refer to the same > declaration in its context and when re-evaluated in the > completed scope of S. > No diagnostic is required for a violation of this rule. > What makes your example illegal is rule 2. I have puzzled over what this rule is trying to say, so perhaps you can illuminate me: I believe, but am not sure, that "the completed scope of S" refers to the scope of S plus the scope of the bodies of all member functions of S. Then, I think "re-evaluated in the completed scope" means that there is another reference to N later in the body of S, or in the body of a member function that it must refer to the same declaration. I can easily be convinced that I don't understand this right, but based on my understanding I agree with Jon that this rule doesn't apply in this case. And, more to the point, I don't think that this rule applies to IDL because in mostly has to do with inlined functions, which don't exist in IDL. Paul Date: Thu, 13 Apr 2000 21:58:26 +1000 (EST) From: Michi Henning Reply-To: Core Revision Task Force To: Core Revision Task Force Subject: 2nd shot at 2980 Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: E^Xd9/&fd9m Michi Henning wrote: > > What makes your example illegal is rule 2. Consider the definition > of U: > > > > module M { > > const long I = 10; > > > > interface A { > > struct S { > > // ... > > }; > > struct U { > > // Point 1 > > long I; // Error? Shouldn't be! > > // Point 2 > > }; > > // ... > > }; > > }; > > > > At point 1, the identifier I resolves to M::I, whereas at point 2, > it > > resolves to U::I. So, the identifier has changed meaning within > the scope > > of U and therefore the definition is ill-formed. > > I don't agree with you or aCC. :-) > > Rule 2 requires that the name be used. At point 1, it has not been > used > in either A or U, so rule 2 should not apply. I think you are right. Rule 2 does indeed not apply. I've stared at the rules for a long time and I can't find anything that would make this illegal either, for the reasons you state. So, I dug a bit deeper and checked with aCC a bit more. It also complains about the following: const long I = 10; struct A { struct S { int x[I]; }; long I; // Error according to aCC }; There is definitely no way for this to result in an alternate program, and I don't see any violation of any rule. So, I got suspicious and dug a bit deeper and found version 1.21 of aCC (I initially tried this with aCC 1.13). aCC 1.21 does not complain. So, serves me right for relying on the compiler more than my brain :-( And thanks for pulling me up on that one, Jon! Now, back to Paul's example: > > module M { > > const long I = 10; > > > > interface A { > > struct S { > > // ... > > }; > > struct U { > > // Point 1 > > long I; // Error? Shouldn't be! > > // Point 2 > > }; > > // ... > > }; > > }; Paul, you are right, this is legal C++. As far as I can see, it should be legal IDL too, simply because there can't be a change of meaning here even if definitions are reordered. So, here is an updated proposal. I hope it's right this time... (Jon, *please* be gentle with me :-) The text below is replacement text for page 3-56 and replaces the paragraph beginning with Once a type identifier has been *used* anywhere within the scope... up to (but excluding) the paragraph Note that redefinitinos of a type after use in a module is OK as in the example: Replacement text: The scope of of a type definition extends from the point of definition to the end of its enclosing scope. (Constant and exception definitions are considered type definitions.) A type is *introduced* into a scope by its use in that scope, if the type name is not a fully-qualified type name. For example: typedef short TempType; // Scope of TempType begins here module M { typedef string ArgType; // Scope of ArgType begins here struct S { ::M::ArgType a1; // Nothing introduced here M::ArgType a2; // M introduced here ::TempType temp; // Nothing introduced here }; // Scope of (introduced) M ends here // ... }; // Scope of ArgType ends here // Scope of global TempType ends here (at end of file) The scope of an introduced type name is from the point of introduction to the end of its enclosing scope. However, if a *type* name is *introduced* into a scope that is nested in an interface or valuetype definition, its *potential* scope extends over the entire enclosing scope and all scopes nested within that scope. (For types that are defined outside an interface or valuetype, the scope and the potential scope are identical.) For example: module M { typedef long ArgType; const long I = 10; typedef short Y; interface A { struct S { struct T { ArgType x[I]; // ArgType and I introduced long y; // a new y is defined, the existing Y // is not used } m; }; typedef string ArgType; // Error: ArgType redefined enum I { I1, I2 }; // Error: I redefined typedef short Y; // OK }; // Potential scope of ArgType and I ends here }; A type may not be redefined within its scope or potential scope, as shown in the preceding example. This rule prevents type names from changing their meaning throughout an interface or valuetype definition, and ensures that reordering of definitions in the presence of introduced types does not affect the semantics of a specification. Note that the following is legal, however: module M { typedef long ArgType; const long I = 10; interface A { struct S { struct T { ArgType x[I]; // ArgType and I introduced } m; }; struct U { long I; // OK, I is not a type name }; enum I { I1, I2 }; // Error: I redefined }; // Potential scope of ArgType and I ends here }; Cheers, Michi. -- Michi Henning +61 7 3891 5744 Object Oriented Concepts +61 4 1118 2700 (mobile) Suite 4, 904 Stanley St +61 7 3891 5009 (fax) East Brisbane 4169 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html From: Paul Kyzivat To: "'Core Revision Task Force'" Subject: RE: 2nd shot at 2980 Date: Tue, 18 Apr 2000 19:04:11 -0400 MIME-Version: 1.0 X-Mailer: Internet Mail Service (5.5.2448.0) Content-Type: text/plain; charset="iso-8859-1" X-UIDL: mJO!!1&Le9lV)e9RQX!! Michi, I have been postponing replying to this because I have been busy, and wanted to do some reading in the C++ standard first. The more I read of the C++ standard the more confused I get and the less inclined I am to want to follow it. It is obscenely complex, largely for reasons that don't apply to IDL. As a result, at the moment I am still groping to find a suitable philosophy or precedent to follow in clarifying scoping for IDL. Meanwhile, I will content myself with pointing out places in your text that I find unclear or inconsistent. See comments below for that. I have snipped your text to just the parts relevant to my comments. Paul > -----Original Message----- > From: Michi Henning [mailto:michi@ooc.com.au] > The text below is replacement text for page 3-56 and replaces > the paragraph > beginning with > > Once a type identifier has been *used* anywhere within > the scope... > > up to (but excluding) the paragraph > > Note that redefinitinos of a type after use in a module is OK as > in the example: > > Replacement text: > > The scope of of a type definition extends from the point of definition > to the end of its enclosing scope. (Constant and exception > definitions are considered type definitions.) A type is > *introduced* into a scope by its use in that scope, if the type > name is not a fully-qualified type name. I don't think the example is consistent with your text. (The example makes more sense to me than the rule does.) It also isn't clear if the scope of the definition is intended to include nested scopes. (I doubt that it should.) > For example: > > typedef short TempType; // Scope of TempType begins here > > module M { > typedef string ArgType; // Scope of ArgType begins here > struct S { > ::M::ArgType a1; // Nothing introduced here > M::ArgType a2; // M introduced here By your rule, I would expect ArgType to be introduced here, although that makes no sense to me. But M, while not a type, is the unqualified name that has to be looked up. Once used here, an argument for consistency might suggest, as you show, that this definition should become the only valid definition in this scope. > ::TempType temp; // Nothing introduced here > }; // Scope of (introduced) M ends here > // ... > }; // Scope of ArgType ends here > > // Scope of global TempType ends here (at end of file) > > The scope of an introduced type name is from the point of > introduction to the end of its enclosing scope. > > However, if a *type* name is *introduced* into a scope that is nested > in an interface or valuetype definition, its *potential* scope > extends over the entire enclosing scope and all scopes nested > within that scope. (For types that are defined outside an interface > or valuetype, the scope and the potential scope are identical.) I must read this differently than you intend. I will rewrite it with annotation in order to talk more specifically: However, if a *type* name is *introduced* into a scope (S1) that is nested in an interface or valuetype definition (S2), its *potential* scope extends over the entire enclosing scope (S?) and all scopes nested within that scope. As I read it, S? should be S1. If you want it to be S2 (and apparently according to the example you do), then I think you need more words to say that. > For example: > > module M { > typedef long ArgType; > const long I = 10; > typedef short Y; > > interface A { > struct S { > struct T { > ArgType x[I]; // ArgType and I introduced > long y; // a new y is defined, the existing Y > // is not used > } m; > }; > typedef string ArgType; // Error: ArgType redefined > enum I { I1, I2 }; // Error: I redefined > typedef short Y; // OK > }; // Potential scope of ArgType and I ends here > }; I can see some logic to what is shown in the example. Without this, there is some apparent ambiguity about where T should draw the definitions of ArgType and I from. > > A type may not be redefined within its scope or potential scope, > as shown in the preceding example. This rule prevents type names > from changing their meaning throughout an interface or valuetype > definition, and ensures that reordering of definitions in > the presence of introduced types does not affect the semantics > of a specification. But in your text here, there seem to be problems. Either the potential scope is the body of T, or it is the body of A. (Depending on whether you meant S1 or S2 above.) If you meant T, then the things you mark as errors aren't, so you must have meant A. However in that case your next example, below, should be illegal even though you say it should be legal: > > Note that the following is legal, however: > > module M { > typedef long ArgType; > const long I = 10; > > interface A { > struct S { > struct T { > ArgType x[I]; // ArgType and I introduced > } m; > }; > struct U { > long I; // OK, I is not a type name > }; > enum I { I1, I2 }; // Error: I redefined > }; // Potential scope of ArgType and I ends here > }; I think the problem is that your definition of potential scope is wrong for your purpose. I think what you want are the scope of the reference, and each containing scope, out to the scope of the interface or valuetype, BUT NOT other scopes nested within the interface or valuetype. (I don't know a concise way to say that.) I would try to help with alternate wording here, but I still don't fully understand what you intend, and I am still without a position of my own. Paul Date: Tue, 7 Nov 2000 17:11:41 +1000 (EST) From: Michi Henning To: Jishnu Mukerji cc: orb_revision@omg.org Subject: Proposal for 2980 In-Reply-To: <39F9ECF8.99231F2B@fpk.hp.com> Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: Y/,!!`Xad9#^fd92AW!! On Fri, 27 Oct 2000, Jishnu Mukerji wrote: > Issue 2980: Problem with the "Special scoping" rules in 3.15.3 - Michi > Henning Yet again, a shot at 2980. I've taken Paul's comments into account. What follows is the previous proposal, but with a changed definition of potential scope. This removes the conflict between the text and the final example that Paul pointed out. Cheers, Michi. -- Michi Henning +61 7 3891 5744 Object Oriented Concepts +61 4 1118 2700 (mobile) Suite 4, 904 Stanley St +61 7 3891 5009 (fax) East Brisbane 4169 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html The text below is replacement text for page 3-56 and replaces the paragraph beginning with Once a type identifier has been *used* anywhere within the scope... up to (but excluding) the paragraph Note that redefinitinos of a type after use in a module is OK as in the example: Replacement text: The scope of of a type definition extends from the point of definition to the end of its enclosing scope. (Constant and exception definitions are considered type definitions.) A type is *introduced* into a scope by its use in that scope, if the type name is not a fully-qualified type name. For example: typedef short TempType; // Scope of TempType begins here module M { typedef string ArgType; // Scope of ArgType begins here struct S { ::M::ArgType a1; // Nothing introduced here M::ArgType a2; // M introduced here ::TempType temp; // Nothing introduced here }; // Scope of (introduced) M ends here // ... }; // Scope of ArgType ends here // Scope of global TempType ends here (at end of file) The scope of an introduced type name is from the point of introduction to the end of its enclosing scope. However, if a *type* name is *introduced* into a scope that is nested in an interface or valuetype definition, its *potential* scope extends over all its enclosing scopes to out to the enclosing interface or valuetype. (For types that are defined outside an interface or valuetype, the scope and the potential scope are identical.) For example: module M { typedef long ArgType; const long I = 10; typedef short Y; interface A { struct S { struct T { ArgType x[I]; // ArgType and I introduced long y; // a new y is defined, the existing Y // is not used } m; }; typedef string ArgType; // Error: ArgType redefined enum I { I1, I2 }; // Error: I redefined typedef short Y; // OK }; // Potential scope of ArgType and I ends here }; A type may not be redefined within its scope or potential scope, as shown in the preceding example. This rule prevents type names from changing their meaning throughout an interface or valuetype definition, and ensures that reordering of definitions in the presence of introduced types does not affect the semantics of a specification. Note that, in the following, the definition of M::A::U::I is legal because it is outside the potential scope of the I introduced in the definition of M::A::S::T::ArgType. However, the definition of M::A::I is still illegal because it is within the potential scope of the I introduced in the definition of M::A::S::T::ArgType. module M { typedef long ArgType; const long I = 10; interface A { struct S { struct T { ArgType x[I]; // ArgType and I introduced } m; }; struct U { long I; // OK, I is not a type name }; enum I { I1, I2 }; // Error: I redefined }; // Potential scope of ArgType and I ends here }; Date: Tue, 07 Nov 2000 10:41:23 -0500 From: Paul Kyzivat X-Mailer: Mozilla 4.73 [en]C-CCK-MCD (WinNT; U) X-Accept-Language: en MIME-Version: 1.0 To: Michi Henning CC: orb_revision@omg.org Subject: Re: Proposal for 2980 References: Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-UIDL: =7J!!D< > On Fri, 27 Oct 2000, Jishnu Mukerji wrote: > > > Issue 2980: Problem with the "Special scoping" rules in 3.15.3 - Michi > > Henning > > Yet again, a shot at 2980. I've taken Paul's comments into account. What > follows is the previous proposal, but with a changed definition of potential > scope. This removes the conflict between the text and the final example > that Paul pointed out. > > Cheers, > > Michi. > -- > Michi Henning +61 7 3891 5744 > Object Oriented Concepts +61 4 1118 2700 (mobile) > Suite 4, 904 Stanley St +61 7 3891 5009 (fax) > East Brisbane 4169 michi@ooc.com.au > AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html > > The text below is replacement text for page 3-56 and replaces the paragraph > beginning with > > Once a type identifier has been *used* anywhere within the scope... > > up to (but excluding) the paragraph > > Note that redefinitinos of a type after use in a module is OK as > in the example: > > Replacement text: > > The scope of of a type definition extends from the point of definition > to the end of its enclosing scope. (Constant and exception > definitions are considered type definitions.) A type is > *introduced* into a scope by its use in that scope, if the type > name is not a fully-qualified type name. For example: > > typedef short TempType; // Scope of TempType begins here > > module M { > typedef string ArgType; // Scope of ArgType begins here > struct S { > ::M::ArgType a1; // Nothing introduced here > M::ArgType a2; // M introduced here > ::TempType temp; // Nothing introduced here > }; // Scope of (introduced) M ends here > // ... > }; // Scope of ArgType ends here > > // Scope of global TempType ends here (at end of file) > > The scope of an introduced type name is from the point of > introduction to the end of its enclosing scope. > > However, if a *type* name is *introduced* into a scope that is nested > in an interface or valuetype definition, its *potential* scope > extends over all its enclosing scopes to out to the enclosing > interface or valuetype. (For types that are defined outside an > interface or valuetype, the scope and the potential scope are > identical.) For example: > > module M { > typedef long ArgType; > const long I = 10; > typedef short Y; > > interface A { > struct S { > struct T { > ArgType x[I]; // ArgType and I introduced > long y; // a new y is defined, the existing Y > // is not used > } m; > }; > typedef string ArgType; // Error: ArgType redefined > enum I { I1, I2 }; // Error: I redefined > typedef short Y; // OK > }; // Potential scope of ArgType and I ends here > }; > > A type may not be redefined within its scope or potential scope, > as shown in the preceding example. This rule prevents type names > from changing their meaning throughout an interface or valuetype > definition, and ensures that reordering of definitions in > the presence of introduced types does not affect the semantics > of a specification. > > Note that, in the following, the definition of M::A::U::I is > legal because it is outside the potential scope of the I introduced > in the definition of M::A::S::T::ArgType. However, the definition > of M::A::I is still illegal because it is within the potential > scope of the I introduced in the definition of M::A::S::T::ArgType. > > module M { > typedef long ArgType; > const long I = 10; > > interface A { > struct S { > struct T { > ArgType x[I]; // ArgType and I introduced > } m; > }; > struct U { > long I; // OK, I is not a type name > }; > enum I { I1, I2 }; // Error: I redefined > }; // Potential scope of ArgType and I ends here > }; Date: Tue, 07 Nov 2000 17:38:48 -0500 From: Jishnu Mukerji Organization: Hewlett-Packard EIAL, Florham Park NJ USA X-Mailer: Mozilla 4.73 [en] (WinNT; U) X-Accept-Language: en MIME-Version: 1.0 To: orb_revision@omg.org Subject: Issue 2980 proposed resolution Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-UIDL: %;:e9b-g!!CAW!!`Xmd9 Proposed resolution constructed out of text provided by Michi. Paul Kyzivat has raised some objection that probably needs some discussion. Other than that this is ready to go. ____________________________________________________________________ Issue 2980: Problem with the "Special scoping" rules in 3.15.3 (orb_revision) Click here for this issue's archive. Source: Floorboard Software (Mr. Jonathan Biggar, jon@floorboard.com) Nature: Uncategorized Issue Severity: Summary: The special scoping rules make it clear that they apply only to identifiers that name a type, however the second IDL example claims that the import of a constant definition (in this case the identifier I) into an interface scope behaves the same way. So which one is it? Do the rules only apply to type identifiers or to all identifiers? Resolution: The changes below provide clarification. Revised Text: The text below is replacement text for page 3-56 and replaces the paragraph beginning with Once a type identifier has been *used* anywhere within the scope... up to (but excluding) the paragraph Note that redefinitinos of a type after use in a module is OK as in the example: Replacement text: The scope of of a type definition extends from the point of definition to the end of its enclosing scope. (Constant and exception definitions are considered type definitions.) A type is *introduced* into a scope by its use in that scope, if the type name is not a fully-qualified type name. For example: typedef short TempType; // Scope of TempType begins here module M { typedef string ArgType; // Scope of ArgType begins here struct S { ::M::ArgType a1; // Nothing introduced here M::ArgType a2; // M introduced here ::TempType temp; // Nothing introduced here }; // Scope of (introduced) M ends here // ... }; // Scope of ArgType ends here // Scope of global TempType ends here (at end of file) The scope of an introduced type name is from the point of introduction to the end of its enclosing scope. However, if a *type* name is *introduced* into a scope that is nested in an interface or valuetype definition, its *potential* scope extends over all its enclosing scopes to out to the enclosing interface or valuetype. (For types that are defined outside an interface or valuetype, the scope and the potential scope are identical.) For example: module M { typedef long ArgType; const long I = 10; typedef short Y; interface A { struct S { struct T { ArgType x[I]; // ArgType and I introduced long y; // a new y is defined, the existing Y // is not used } m; }; typedef string ArgType; // Error: ArgType redefined enum I { I1, I2 }; // Error: I redefined typedef short Y; // OK }; // Potential scope of ArgType and I ends here }; A type may not be redefined within its scope or potential scope, as shown in the preceding example. This rule prevents type names from changing their meaning throughout an interface or valuetype definition, and ensures that reordering of definitions in the presence of introduced types does not affect the semantics of a specification. Note that, in the following, the definition of M::A::U::I is legal because it is outside the potential scope of the I introduced in the definition of M::A::S::T::ArgType. However, the definition of M::A::I is still illegal because it is within the potential scope of the I introduced in the definition of M::A::S::T::ArgType. module M { typedef long ArgType; const long I = 10; interface A { struct S { struct T { ArgType x[I]; // ArgType and I introduced } m; }; struct U { long I; // OK, I is not a type name }; enum I { I1, I2 }; // Error: I redefined }; // Potential scope of ArgType and I ends here }; __________________________________________________________________ Comments? Jishnu. Date: Wed, 8 Nov 2000 11:16:32 +1000 (EST) From: Michi Henning To: Paul Kyzivat cc: orb_revision@omg.org Subject: Re: Proposal for 2980 In-Reply-To: <3A0822A3.78BF20D9@cisco.com> Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: oMbd9cPCe9Y!R!!^7F!! On Tue, 7 Nov 2000, Paul Kyzivat wrote: > Since I am no longer a voting member of the rtf, take this for what its > worth... > (I just can't resist mouthing off now and then.) Don't let that worry you Paul. I did the same thing for years, long before I ever had a vote :-) > What is troubling to me about this formulation of the rule is that it > singles out interfaces and valuetypes for special treatment, but I can > see no justification for that special treatment. OK. The justification is that interfaces and valutypes map to classes, and that the scope resolution rules for classes are tighter than for namespaces. Basically, the rules are designed such that an innocent change somewhere in a scope that is nested inside a class cannot inadvertently change the meaning of a program. > The arguments I *have* heard that justify special treatment are for > modules. > They are different because they may be reopened. It appears to me > that > "interfaces and valuetypes" is being used as a synonym for "not > module", > even though that isn't quite the same. Modules, which map to namespaces, have rules that not quite as strict as classes. That's because, for namespaces, there is no problem with things changes in a base class and then affecting the derived class. > It would make much more sense to me to define potential scope as > extending over all the enclosing non-module scopes that intervene > between the scope holding the definition and point of introduction. No, I think what I suggested is right. Cheers, Michi. -- Michi Henning +61 7 3891 5744 Object Oriented Concepts +61 4 1118 2700 (mobile) Suite 4, 904 Stanley St +61 7 3891 5009 (fax) East Brisbane 4169 michi@ooc.com.au AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html Reply-To: From: "Nick Sharman" To: "Michi Henning" , "Paul Kyzivat" Cc: Subject: RE: Proposal for 2980 Date: Wed, 8 Nov 2000 10:05:49 -0000 Message-ID: MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Priority: 3 (Normal) X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook IMO, Build 9.0.2416 (9.0.2910.0) Importance: Normal X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2314.1300 In-Reply-To: Content-Type: text/plain; charset="iso-8859-1" X-UIDL: pYMe9QL-!!C`;e9l,2!! Michi, I think Paul's point is that there are scopes _other_ than interface, valuetype and module - especially struct and union. For example: module M { typedef long L; struct S { struct T { L long_field; // introduces L from M } t_member; struct L { // ??? char c; } l_member; }; }; Since structs & unions map to C++ and Java classes to, they impose naming constraints similar to those on interfaces and valutypes. As Paul suggests, a global edit changing "interface or valuetype" to "non-module scope" probably does the trick. Regards Nick > -----Original Message----- > From: Michi Henning [mailto:michi@ooc.com.au] > Sent: Wednesday, November 08, 2000 1:17 AM > To: Paul Kyzivat > Cc: orb_revision@omg.org > Subject: Re: Proposal for 2980 > > > On Tue, 7 Nov 2000, Paul Kyzivat wrote: > > > Since I am no longer a voting member of the rtf, take this for what its > > worth... > > (I just can't resist mouthing off now and then.) > > Don't let that worry you Paul. I did the same thing for years, long before > I ever had a vote :-) > > > What is troubling to me about this formulation of the rule is that it > > singles out interfaces and valuetypes for special treatment, but I can > > see no justification for that special treatment. > > OK. The justification is that interfaces and valutypes map to classes, and > that the scope resolution rules for classes are tighter than for > namespaces. > Basically, the rules are designed such that an innocent change somewhere > in a scope that is nested inside a class cannot inadvertently change > the meaning of a program. > > > The arguments I *have* heard that justify special treatment are for > > modules. > > They are different because they may be reopened. It appears to me that > > "interfaces and valuetypes" is being used as a synonym for "not module", > > even though that isn't quite the same. > > Modules, which map to namespaces, have rules that not quite as strict > as classes. That's because, for namespaces, there is no problem > with things > changes in a base class and then affecting the derived class. > > > It would make much more sense to me to define potential scope as > > extending over all the enclosing non-module scopes that intervene > > between the scope holding the definition and point of introduction. > > No, I think what I suggested is right. > > Cheers, > > Michi. > -- > Michi Henning +61 7 3891 5744 > Object Oriented Concepts +61 4 1118 2700 (mobile) > Suite 4, 904 Stanley St +61 7 3891 5009 (fax) > East Brisbane 4169 michi@ooc.com.au > AUSTRALIA http://www.ooc.com.au/staff/michi-henning.html > > Date: Thu, 9 Nov 2000 12:26:16 +1000 (EST) From: Michi Henning To: Nick Sharman cc: Paul Kyzivat , orb_revision@omg.org Subject: RE: Proposal for 2980 In-Reply-To: Message-ID: Organization: Object Oriented Concepts MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII X-UIDL: T2Ae9`&)e9I_K!!fNXd9 On Wed, 8 Nov 2000, Nick Sharman wrote: > I think Paul's point is that there are scopes _other_ than interface, > valuetype and module - especially struct and union. > > For example: > > module M { > typedef long L; > struct S { > struct T { > L long_field; // introduces L from M > } t_member; > struct L { // ??? > char c; > } l_member; > }; > }; > > Since structs & unions map to C++ and Java classes to, they impose naming > constraints similar to those on interfaces and valutypes. As Paul suggests, > a global edit changing "interface or valuetype" to "non-module scope" > probably does the trick. Yes, you are right. The equivalent of the above in C++ is actually illegal because reordering the definitions inside S such that L would precede T would change the meaning (long_field's type would change to a struct in that case). So, can we put this baby to bed by making the change suggested by Nick? (To mix metaphors, this is one of the most difficult births of any issue I can remember, possibly with the exception of 3425 :-) Cheers, Michi. Date: Thu, 09 Nov 2000 11:03:53 -0500 From: Jishnu Mukerji Organization: Hewlett-Packard EIAL, Florham Park NJ USA X-Mailer: Mozilla 4.73 [en] (WinNT; U) X-Accept-Language: en MIME-Version: 1.0 To: Michi Henning Cc: Nick Sharman , Paul Kyzivat , orb_revision@omg.org Subject: Re: Proposal for 2980 References: Content-Transfer-Encoding: 7bit Content-Type: text/plain; charset=us-ascii X-UIDL: ei$!!B7?!!(_;e9_93e9 Michi Henning wrote: > > On Wed, 8 Nov 2000, Nick Sharman wrote: > > > I think Paul's point is that there are scopes _other_ than interface, > > valuetype and module - especially struct and union. > > > > For example: > > > > module M { > > typedef long L; > > struct S { > > struct T { > > L long_field; // introduces L from M > > } t_member; > > struct L { // ??? > > char c; > > } l_member; > > }; > > }; > > > > Since structs & unions map to C++ and Java classes to, they impose naming > > constraints similar to those on interfaces and valutypes. As Paul suggests, > > a global edit changing "interface or valuetype" to "non-module scope" > > probably does the trick. > > Yes, you are right. The equivalent of the above in C++ is actually > illegal because reordering the definitions inside S such that L > would precede T would change the meaning (long_field's type would change > to a struct in that case). > > So, can we put this baby to bed by making the change suggested by Nick? > > (To mix metaphors, this is one of the most difficult births of any > issue I can remember, possibly with the exception of 3425 :-) > Sure. Consider it done. Jishnu.