!standard 03.10.01 (02) 03-12-11 AI95-00326/05 !standard 03.10.01 (04) !standard 03.10.01 (05) !standard 03.10.01 (08) !standard 03.10.01 (09) !standard 03.10.01 (10) !standard 03.10.01 (11) !standard J.11 (00) !class amendment 02-02-06 !status work item 03-07-30 !status ARG Approved 10-0-1 03-07-15 !status work item 02-12-13 !status received 02-02-06 !priority Medium !difficulty Medium !subject Tagged incomplete types !summary A concept of a "tagged incomplete" type is introduced, which is a type that has the same restrictions as an incomplete type except that it may also be used for a formal or actual parameter. !problem For mutually recursive types, it is valuable if subprogram parameters may be of the type itself, rather than only an access to the type. However, for most types, it may be necessary to see the full definition to know how parameters of the type are passed. However, because tagged types are always passed by reference, there is no implementation difficulty in allowing them to be used as parameters even when the full definition of the type is not available. Hence, it makes sense to relax the rule for using incomplete types that are known to be tagged, to allow them as formal parameters, since from a code generation point of view they are essentially equivalent to access parameters. !proposal The syntax for an incomplete type declaration is amended as follows: incomplete_type_declaration ::= TYPE defining_identifier [discriminant_part] [IS TAGGED]; If the words IS TAGGED appear, the type is a tagged incomplete type. Otherwise, the type is a non-tagged incomplete type. In addition to places where a (non-tagged) incomplete type may be used, a tagged incomplete type may be used as a formal parameter type, and a dereference of an access to tagged incomplete can be used as an actual parameter. The attribute 'Class is defined for (specific) tagged incomplete types. (The use of 'Class with non-tagged incomplete types is considered obsolescent; such non-tagged incomplete types must be completed with a tagged type.) The class-wide type denoted by the Class attribute of an incomplete tagged type is also an incomplete tagged type. An incomplete tagged type declaration must be completed by a tagged type declaration. !wording Note: This wording includes the changes needed to support AI-217-6. These rules are marked. Replace 3.2(4) by: The composite types are the record types, record extensions, array types, task types, and protected types. There can be multiple views of a type with varying sets of operations. An incomplete type represents an incomplete view (see 3.10.1) of a type with a very restricted usage, providing support for recursive data structures. A private type or private extension represents a partial view (see 7.3) of a type, providing support for data abstraction. The full view (see 3.2.1) of a type provides its complete declaration. An incomplete or partial view is considered a composite type. AARM: Only the first and last sentences really define anything; the real definitions of the views are in the referenced paragraphs. Modify 3.2(5): Certain composite types (and [partial] views thereof) have special... Add to 3.2.1(8) before the last sentence: A full type defines the full view of a type. AARM Change: All types have full views in this model. The penultimate sentence of 7.3(4) gets square brackets in the RM (but I'd recommend leaving it there in order to keep the entire private type model intact). Modify 3.7(1) to remove the two occurrences of "partial" in the second sentence. Note: Incomplete views can have unknown_discriminant_parts, and this wording should reflect that. Since full views cannot have unknown_discriminant_parts, "view of a type" is enough here. Replace 3.10.1(2): incomplete_type_declaration ::= TYPE defining_identifier [discriminant_part] [IS TAGGED]; Modify 3.10.1(4): Add two new first sentences: If an incomplete_type_declaration includes the keyword TAGGED, then the type_declaration that completes it shall declare a tagged type. Such an an incomplete_type_declaration declares a tagged incomplete view. In the other sentences, replace "full_type_declaration" with "type_declaration". Replace 3.10.1(5-9): A name that denotes an incomplete view of a type may be used as follows: * as the subtype_mark in the subtype_indication of an access_to_object_definition; the only form of constraint allowed in this subtype_indication is a discriminant_constraint; * as the subtype_mark in an access_definition; If such a name denotes a tagged incomplete view, it may also be used: * as the subtype_mark defining the subtype of a parameter in a formal_part; * as the prefix of an attribute_reference whose attribute_designator is Class; such an attribute_reference is restricted to the uses allowed above for tagged incomplete views. If such a name occurs within the list of declarative_items containing the completion of the incomplete view, it may also be used: * as the subtype_mark defining the subtype of a parameter or result of an access_to_subprogram_definition; If any of the above uses occurs as part of the declaration of a primitive subprogram of the incomplete view, and the declaration occurs immediately within the private part of a package, then the completion of the incomplete view shall also occur immediately within the private part; it may not be deferred to the package body. AARM: This fixes a hole in Ada 95 where a dispatching operation with an access parameter could be declared in a private part and a dispatching call on it could occur in a child even though there is no visibility on the full type, requiring access to the controlling tag without access to the representation of the type. Replace 3.10.1(10): The prefix of a name shall not be of an incomplete view. AARM: We used to disallow all dereferences of an incomplete type. Now we only disallow such dereferences when used as a prefix. Dereferences used in other contexts do not pose a problem since normal type matching will preclude their use except when the full type is "nearby" as context (e.g. as the expected type). TBD: What about assignment statements? Is an incomplete type limited or nonlimited? Replace 3.10.1(11): An incomplete_type_declaration declares an incomplete view of a type, and its first subtype; the first subtype is unconstrained if a known_discriminant_part appears. AARM Change: We define "incomplete view" here. Given an access type A whose designated type T is an incomplete view, a dereference of a value of type A is also of this incomplete view except when: * it occurs in the immediate scope of the completion of T, or * it occurs in the scope of a nonlimited_with_clause that mentions a library package in whose visible part the completion of T is declared. AARM Note: We need the "in whose visible part" rule so that the second rule doesn't trigger in the body of a package with a with of a child unit: package P is private type T; type AT is access T; end P; private package P.C is Ptr : AT; end P.C; with P.C; package body P is -- Ptr.all is not legal here, but it is in the scope of a non-limited -- with_clause for P. type T is ... -- Ptr.all is legal here. end P; AI-217 Note: The above rules comes from AI-217-06. Note that here we say that the view is complete, and thus none of the restrictions outlined in this section apply, not just dereferencing as the AI-217-6 wording said. I believe that is what was intended (it certainly is what *I* thought was intended). A dereference (whether implicit or explicit -- see 4.1) shall not be of an incomplete view, unless: * its expected type is not an incomplete view of T; AARM Note: This means that it is a partial or full view of T. We don't enumerate the kinds of views to make it easier to add other kinds of views in the future. AI-217 Note: This also comes from AI-217. * it is a tagged incomplete view and it is used as an actual parameter of a call, or the expression of a qualified_expression or parenthesized expression used in one of these contexts. AARM Note: Dispatching calls are prohibited for incomplete views (see 3.9.2), so this is mainly useful in class-wide calls. AARM To Be Honest: This really means "top-level" actual parameter with arbitrary qualified_expressions and parents. We can't allow it to occur as the operand of a type conversion, membership operation, or predefined equality. Since equality is a function, it is already covered by these rules, but the other cases aren't. *** Open issue: Alternative wording could say "...it is used in the expression or name of an actual parameter of a call, but not as the operand of a type conversion or membership operation." But that brings up the possibility of missing a problem case. 4.1(9): No change is needed. Note that this differs from the proposed AI-217-6. Modify 13.1(11/1): Replace the second sentence by: Operational and representational aspects are the same for all views of a type. Note: This change isn't strictly necessary; you can't actually tell those aspects for an incomplete view. But it is an important part of the "view of a type" model. We could add a clarification like "Thus, the aspects of an incomplete or partial view are the same as those of the full view of the type." Add J.11: J.11 The Class Attribute of Non-tagged Incomplete Types For the first subtype S of a type T declared by an incomplete_type_declaration that is not tagged, the following attribute is defined: S'Class Denotes the first subtype of the incomplete class-wide type rooted at T. The completion of T shall declare a tagged type. Such an attribute reference shall occur in the same library unit as the incomplete_type_declaration. !discussion Tagged type hierarchies often have need for mutually dependent types. By allowing a tagged incomplete type to be used as a formal parameter type, access parameters may be avoided in such mutually dependent type situations. This proposal gains additional power when combined with the proposals for allowing mutually dependent types to be defined in separate packages. We are not allowing an incomplete tagged type to be used as a return type, because of the many special rules and implementation issues associated with returning tagged types (e.g. abstract types may not be used as result types, functions that must be overridden, accessibility checks on returning limited by-reference types, dispatching on result coupled with tag indeterminacy, finalization associated with returning potentially controlled types, etc.). 3.2.1(8) is the only place where an incomplete type is described as a "view". Elsewhere in the standard, it is described as a separate type. However, the separate type model has a number of bad effects (for instance, nowhere in the standard does it say that an incomplete type matches its completing type - if the types are different, that's necessary). Moreover, private types are described in the standard as a partial view of a type. An incomplete type is just another kind of restricted view, so it is very strange that the description is completely different. In addition, incomplete types are omitted from various text in the standard; if they're separate types, there would be quite a bit of patching to do. Thus, the wording generalizes the concept "view of a type" to encompass incomplete views as well as partial views. We considered generalizing the concept of a "partial view of a type" instead. However, that led to lengthy terms for specific kinds of partial views: "tagged incomplete partial view" and "limited private partial view" are just too unwieldy. A possible hole was discovered during this discussion: package P is ... private type T1; type AT1 is access all T1'Class; P1 : AT1; type T2 is tagged; type AT2 is access all T2'Class; P2 : AT2; end P; private package P.C is procedure Foo (P : access T1); procedure Bar (P : T2); procedure Test; end P.C; package body P.C is procedure Test is begin Foo (P.P1); -- A dispatching call! (Ada 95) Bar (P.P2.all); -- A dispatching call! (Ada 0Y) end Test; end P.C; If the body of P sets P1 and P2 to objects, the calls to Foo and Bar are dispatching calls and logically ought to work. But the location of the tags for T1 and T2 are unknown when the calls are compiled. Therefore, we add a rule to make dispatching calls when the dispatching type is incomplete illegal. Dereferences of incomplete tagged types are still be useful for class-wide calls. For instance (presuming AI-217-6 is approved): limited with Departments; package Employees is type Employee is private; procedure Assign (E : Employee; D : Departments.Department'Class); type Dept_Ptr is access Departments.Department'Class; end Employees; with Employees; procedure Recruit (D : Employees.Dept_Ptr; E : Employees.Employee) is begin Employees.Assign (E, D.all); end Recruit; From the perspective of Recruit, a Departments.Department is just a black box that Employees uses and it was passed and is passing along. It would be bizarre for Recruit to have to with Departments simply to be able to call Assign. !example --*** Will redo the !corrigendum in the future. --!corrigendum 3.10.1(2) -- --@drepl --@xindent<@fa defining_identifier [discriminant_part];>> --@dby --@xindent<@fa defining_identifier [discriminant_part] [@b]; -- --!corrigendum 3.10.1(4) -- --@drepl --If an @fa has a @fa, then --a @fa that completes it shall have a fully conforming --(explicit) @fa (see 6.3.1). If an --@fa has no @fa (or an --@fa), then a corresponding @fa --is nevertheless allowed to have discriminants, either explicitly, or inherited --via derivation. --@dby --If an @fa includes the keyword @b, then a --@fa that completes it shall declare a tagged type. --If an @fa has a @fa, then --a @fa that completes it shall have a fully conforming --(explicit) @fa (see 6.3.1). If an --@fa has no @fa (or an --@fa), then a corresponding @fa --is nevertheless allowed to have discriminants, either explicitly, or inherited --via derivation. -- --!corrigendum 3.10.1(5) -- --@drepl --The only allowed uses of a name that denotes an @fa --are as follows: --@dby --A name that denotes an @fa may be used as follows: -- --!corrigendum 3.10.1(8) -- --@drepl --@xbullet in an @fa;> --@dby --@xbullet in an @fa.> -- --A name that denotes an incomplete_type_declaration that includes the --keyword @b may also be used as follows: -- --@xbullet defining the subtype of a parameter in a --@fa;> -- --!corrigendum 3.10.1(9) -- --@drepl --@xbullet of an @fa whose --@fa is Class; such an @fa is --similarly restricted to the uses allowed here; when used in this way, the --corresponding @fa shall declare a tagged type, and the --@fa shall occur in the same library unit as the --@fa.> --@dby --@xbullet of an @fa whose --@fa is Class; such an @fa is --restricted to the uses allowed above.> -- --!corrigendum 3.10.1(10) -- --@drepl --A dereference (whether implicit or explicit -- see 4.1) shall not be --of an incomplete type. --@dby --A dereference (whether implicit or explicit -- see 4.1) shall not be --of an incomplete type, unless it is directly used as an actual --parameter where the expected type is a class-wide tagged incomplete type. -- --!corrigendum 3.10.1(11) -- --@drepl --An @fa declares an incomplete type and its first --subtype; the first subtype is unconstrained if a @fa --appears. --@dby --An @fa declares an incomplete type and its --first subtype; the incomplete type is tagged if the keyword @b --appears; the first subtype is unconstrained if a @fa --appears. -- --!corrigendum J.11(1) -- --@dinsc --For the first subtype S of a type T declared by an --@fa that is not tagged and is not a type stub, the --following attribute is defined: -- --@xhang<@xtermDenotes the first subtype of the incomplete class-wide --type rooted at T. The completion of T shall declare a tagged type. Such an --attribute reference shall occur in the same library unit as the --@fa. !ACATS Test ACATS B and C tests should be constructed for this AI. !appendix This AI was split out of AI-00217-05 (and other variants), in order to simplify those proposals and to insure that this idea gets considered no matter which of those proposals is adopted. ************************************************************* From: Randy Brukardt Sent: Tuesday, July 15, 2003 2:25 PM In Toulouse, we discussed whether we could allow dereferences of tagged incomplete types. In general, the answer is no, because we cannot know where tags and discriminants are going to be stored in the completing type. (If the type is completed in the body, for instance.) The conversation in Toulouse focused on dispatching calls. Clearly, we cannot allow dispatching calls because we don't know where the tag is stored (presuming the implementation allows positioning it, as Rational Apex and Janus/Ada do). However, there is no problem with class-wide calls, and these could be useful. The key is that we can only allow "whole-object" dereferences when the dereference is immediately passed as a reference parameter. This would look something like: package Typ is type T is tagged; type AT is access all T; procedure Op1 (Obj : in out T'Class); procedure Op2 (Obj : in out T); ... end Typ; with Typ; procedure User is ... P : Typ.AT := ...; ... Typ.Op1 (P.all); -- Allowed? (No implementation problem). Typ.Op2 (P.all); -- Can't allow (don't know where the tag is). ... end User; Note that Op1 could be used as a work-around to implement Op2 if that was necessary (as the body of Typ.Op1 certainly could dispatch to Op2). This rule would be on the messy side (it pretty much could only allow dereferences when used as a non-dispatching actual parameter) and I haven't tried to figure out the wording. Should we pursue this, or leave that AI without any means of making a call? ************************************************************* From: Randy Brukardt Sent: Tuesday, July 15, 2003 2:41 PM I neglected to mention that class-wide parameters would be the most likely way that a tagged incomplete type would be used from a limited with (you almost always should avoid non-dispatching specific tagged parameters, because they cause trouble if there is an extension). So, such a class-wide call may not be rare: package Office is type Department is tagged private; type Dept_Ptr is access all Department'Class; private ... end Office; limited with Office; package Employees is type Employee is tagged private; type Emp_Ptr is access all Employee'Class; procedure Assign_Employee(E : in out Employee; D : in out Office.Department'Class); ... function Current_Department(D : in Employee) return Office.Dept_Ptr; private ... end Employees; with Employees, Repository; procedure RRS is Randy, Ian, Isaac : Employees; begin -- Add a new employee in Randy's department: Repository.Read (Randy); Employees.Assign_Employee (Isaac, Employees.Current_Department (Randy).all); Repository.Write (Isaac); end RRS; The call to Assign_Employee is illegal for a tagged incomplete type. We'd have to with Office to make it legal, which is annoying, since this has little to do with Office. (And, if we adopt a special rule to make it legal here, which we've discussed, then it ought to be legal for tagged incomplete as well -- otherwise, we'd have a weird inconsistency.) ************************************************************* From: Tucker Taft Sent: Tuesday, July 15, 2003 2:46 PM I would suggest we keep it as simple as possible. If at some later point we think we can open it up more, that is possible, but a really complex rule probably doesn't help anyone at this point. I like your suggestion of allowing class-wide incomplete types only, and disallow any calls with parameters of a non-class-wide incomplete type. That seems pretty simple to define and enforce. I suppose we need to worry about S'Class, where subtype S is T(discrim => value). It seems the prefix of the Class attribute must be the first subtype. ************************************************************* From: Robert I. Eachus Sent: Tuesday, July 15, 2003 8:28 PM Tucker Taft wrote: ... >I like your suggestion of allowing class-wide incomplete types only, >and disallow any calls with parameters of a non-class-wide >incomplete type. Sounds reasonable. > That seems pretty simple to define and >enforce. I suppose we need to worry about S'Class, where >subtype S is T(discrim => value). It seems the prefix of the >Class attribute must be the first subtype. This sent me scurrying off to the AARM, which was perfectly unclear: 3.9 (15) S'Class is unconstrained. However, if S is constrained, then the values of S'Class are only those that when converted to the type T belong to S. 3.9(15b) Note that if S is constrained, S'Class is only partially constrained, since there might be additional discriminants added in descendants of T which are not constrained. In any case, I don't see that your proposed restriction buys anything. I think you are trying to avoid cases where there is a subtype that is more constrained than the base class. But in theory I could restructure things so that S was a first subtype with the same discriminant constraints. So as long as S'Class is allowed where S is a derived type, I don't see the limitation accomplishing anything other than confusing Ada programmers. In any case, since the (class-wide) name must appear in a context where it is going to be resolved by run-time dispatching, any freezing issues are long gone. ************************************************************* From: Tucker Taft Sent: Tuesday, July 15, 2003 2:46 PM It is important we don't allow "partially" constrained subtypes of an incomplete type as actuals, since the caller doesn't know where the discriminants are. However, perhaps we are safe, since named subtypes of incomplete types aren't allowed, so it would not be possible to declare a named subtype S, and hence there would be no way to write a partially constrained (incomplete class-wide) subtype S'Class. ************************************************************* From: Robert I. Eachus Sent: Wednesday, July 16, 2003 11:38 AM Tucker Taft wrote: > It is important we don't allow "partially" constrained > subtypes of an incomplete type as actuals, since the > caller doesn't know where the discriminants are. > However, perhaps we are safe, since named subtypes > of incomplete types aren't allowed, so it would not > be possible to declare a named subtype S, and hence > there would be no way to write a partially constrained > (incomplete class-wide) subtype S'Class. > But the caller may also be passing an object of a type (not subtype) that is totally unknown where the call is made. That is the nature of calls with class-wide formals. Let me give an example of the full horror, and you will see that compilers SHOULD be handling it correctly now: package P is type T(Some: Discriminants) is tagged....; subtype S is T(This_Discriminant); function Some_Function(SP: S) return Integer; end P; with P; use P; package U is procedure Some_Proc(TC: in T'Class); end U; package body U is procedure Some_Proc(TC: in T'Class) is I: Integer := Some_Function(TC); -- discriminant check is here... begin null; end; end U; package Q is type R is new T with private; private ... end Q; with P, Q, U; use P, Q, U; procedure Main is QR: R; begin Some_Proc(QR); end Main; I think that gets it. The discriminant check on the call to Some_Function has to be made by code that doesn't even know that type R will exist. I don't know how current compilers handle this, I have been assuming that if they let users control the layout of discriminants in derived types that the dispatch table includes a thunk for finding discriminants. ************************************************************* From: Robert I. Eachus Sent: Wednesday, July 16, 2003 12:02 PM I think I just misspoke in my example, but it doesn't change the issue. The discriminant check occurs after a view conversion to the subtype of the formal parameter, but the function I used in my example is illlegal where it is declared. (The legality rule in 3.9.2(10/1) prevents it.) So change the example to: package P is type T(Some: Discriminants) is tagged....; subtype S is T(This_Discriminant); function Some_Function(SP: S'Class) return Integer; -- or worse function Some_Other_Function(SP: S'Class) return T; -- now it is dispatching, but the parameter with the subtype check is classwide. end P; with P; use P; package U is procedure Some_Proc(TC: in T'Class); end U; package body U is procedure Some_Proc(TC: in T'Class) is I: Integer := Some_Function(TC); -- discriminant check is here... begin null; end; end U; package Q is type R is new T with private; private ... end Q; with P, Q, U; use P, Q, U; procedure Main is QR: R; begin Some_Proc(QR); end Main; ************************************************************* From: Randy Brukardt Sent: Wednesday, July 23, 2003 6:53 PM Robert Eachus wrote: .. > I think that gets it. The discriminant check on the call to > Some_Function has to be made by code that doesn't even know that type R > will exist. I don't know how current compilers handle this, I have been > assuming that if they let users control the layout of discriminants in > derived types that the dispatch table includes a thunk for finding > discriminants. 13.5.1(14) says that the layout of a parent part (obviously including the discriminants) can't be changed by a record rep. clause. Note that this is a RULE, not a "recommended level of support" -- compilers are not allowed to change the layout of the parent part. So there is no problem here. ************************************************************* From: Robert I. Eachus Sent: Thursday, July 24, 2003 5:44 PM The intent in my example was to have a call on the parent type have to perform a discriminant check necessary because of a subtype of the child type. But I see that Randy is right. A derived type can add a variant part, but it has to depend on an existing discriminant. So as far as the compiler is concerned there is no difference between a subtype of a derived (tagged) type and a subtype of the parent. ************************************************************* From: Randy Brukardt Sent: Wednesday, September 17, 2003 2:05 PM I'm working on the wording for tagged incomplete types, and I need a bit of help. The Standard makes it clear that an incomplete type is a separate type from the completion. (This is very different than the situation for private types. This formulation was inherited from Ada 83.) But that doesn't seem to be reflected in the type matching rules. For instance: (I've marked the incomplete type with an [I] and the complete type with a [C] for clarity) type D[I]; type Acc_D is access all D[I]; type D[C] is ...; P : Acc_D := new D[C]; Where is the rule that says that D[C] is allowed to match D[I] for resolution purposes? Now, we all *know* this works. The question is merely where does the RM say that. If it doesn't, of course, we have another hole to fix, which should be taken into account when writing the wording. ************************************************************* From: Randy Brukardt Sent: Thursday, November 20, 2003, 11:20 PM Following is an analysis of the RM wrt to making an incomplete view a type of partial view. Various uses of "partial view" would need to be qualified with "private". Appendix: All references to "incomplete type" in the AARM other than 3.10.1. 3.1(12.i): informal use. 3.2.1(26.c): informal use. 3.9(15.c): informal use. 7.1(17.c): Applies to type decl, no changes needed. 13.14(1.j): informal use. 13.14(3/1): Applies to type decl, no changes needed. 13.14(3.b): informal use. B.1(26.b): Applies to type decl, no changes needed. --- Appendix: All references to "partial view" in the AARM. 3.7(1): use of unknown discriminants. OK unchanged. (3.10.1 definitely allows unknown_discriminants on incomplete types; but it is not clear that this rule does.) 3.7(26.c): Same as above. 13.1(11/1): Same rep. for both views. Harmless to say (even though you can't query those aspects). 8.3(10.b): An AARM note, and appears true. This is discussing primitive operations. It appears that incomplete types have primitive operations by 3.2.3(6), so the note seems to be true. package Foo is ... private type Arg; procedure Goody (P : access Arg); -- Primitive for Arg. end Foo; 7.5(1.c): An AARM note (about limited types completed by non-limited types). Probably fine as is (and probably wrong because of AI-287 anyway). 3.9.3(9): Says that the full view of a non-abstract partial view must not be abstract. Seems to need change (can an incomplete type be completed by an abstract type? I think so.) 3.9.2(12.a.1/1): An AARM note that says that the rule against multiple dispatching applies to full views. (This was a ramification published in the defect reports.) Does this apply to incomplete types? Looks ugly either way: package Foo2 is ... private type Arg2; type Arg3; procedure Yikes (P : access Arg2; P2 : access Arg3); end Foo2; package body Foo2 is type Arg2 is tagged... type Arg3 is tagged... ... end Foo2; Is Yikes illegal? Where is the check made? Of course, if these were a tagged incomplete types it would be easier to check. So I think that this note is correct, and should stand, even for incomplete partial views. 3.9(2): Discusses a particular kind of partial view. No change needed. 3.4(24): Discusses more particular kinds of partial view. No change needed. 7.3.1(10-13): These notes describe operations of private partial views. They'd need to be qualified. But they're notes - no big deal. 3.2(2.p): Defines the glossary entry for "private type". Its "A partial view", it isn't exclusive. 3.2(4): A private type represents a partial view. No problem. Also, a partial view is composite. Humm. I don't think that is a problem, either, given how little can be done with an incomplete view. 3.2(5): Partial views may have discriminants. That's fine. Indeed, it looks like incomplete types were completely omitted from this section, which seems a bit weird. They're not that different from private types. 7.3(4): A private type declares a partial view. That probably would be OK without change, but it would be a bit confusing. Also, we would probably want to introduce the qualifier "private" here. The part about a partial view requiring a completion would have to change to "private partial view". 7.3(5): This is bracketed in the AARM to mean "redundant". It's also true of incomplete types - but a bit confusing. 7.3(6): This would have to be qualified as "private partial view" (no such thing as a limited incomplete type, nor are there any restrictions on completion). 7.3(7): The third sentence would have to be qualified. As would the following AARM notes (which I won't list here). 7.3(9): Incomplete types have the same rule; we could get rid of one of the copies. 7.3(10.a): AARM note, which is OK. 7.3(11): This already applies to incomplete types. Another rule we could get rid of. 7.3(12): Applies only to private types, would have to be qualified. 7.3(15): The first sentence applies to both; the rest (which probably ought to be split out) only apply to private types. 7.3(17): Specific uses of partial view; no change would be required. 7.3(18): Specific use of partial view; no change would be needed. 3.2.1(8): "partial and incomplete view". Humm. *************************************************************