!standard 13.01 (10-11) 00-03-07 AI95-00137/03 !class binding interpretation 96-05-07 !status Corrigendum 2000 99-07-28 !status WG9 approved 96-12-07 !status ARG approved 6-0-2 96-06-17 !status work item 96-05-08 !status received 96-05-07 !priority High !difficulty Medium !qualifier Error !subject Attribute definition clause for Stream Attributes !summary 13.1(10) says: 10 For an untagged derived type, no type-related representation items are allowed if the parent type is a by-reference type, or has any user-defined primitive subprograms. This rule does not apply to an attribute_definition_clause for one of the stream-oriented attributes Read, Write, Input, and Output. !question 13.1(10) seems to forbid the following example: with Ada.Streams; use Ada.Streams; generic type T is private; package Attr_Rep is type NT is new T; procedure Attribute_Write( Stream : access Root_Stream_Type'Class; Item : in NT); for NT'Write use Attribute_Write; -- Illegal? (No.) end Attr_Rep; !recommendation (See summary.) !wording (See corrigendum.) !discussion The intent of 13.1(10) is to forbid two types from having different representation in certain cases. However, the stream-oriented attributes, although they are formally defined to be "representation attributes", do not actually affect the representation of the type. Therefore, there is no need for 13.1(10) to apply to these attributes. Furthermore, as the example illustrates, applying the rule to these attributes would seriously hinder their usefulness. The definition of stream attributes as "representation attributes" has proven to be a continuing problem. Several issues have made it necessary to except stream attributes from the rules for representation attributes, enough that it is clear that they are not representation attributes. Therefore, we take the major step of defining a new kind of attribute, the "operational attributes", and redefining stream attributes to be of this kind. !corrigendum 3.08(05) @drepl @xcode<@fa> @dby @xcode<@fa> !corrigendum 3.11(04) @drepl @xcode<@fa> @dby @xcode<@fa> !corrigendum 9.01(05) @drepl @xcode<@fa> @dby @xcode<@fa> !corrigendum 9.04(05) @drepl @xcode<@fa> @dby @xcode<@fa> !corrigendum 9.04(08) @drepl @xcode<@fa> @dby @xcode<@fa> !corrigendum 13.01(01) @drepl There are three kinds of @i: @fa, @fa, and @i. Representation items specify how the types and other entities of the language are to be mapped onto the underlying machine. They can be provided to give more efficient representation or to interface with features that are outside the domain of the language (for example, peripheral hardware). Representation items also specify other specifiable properties of entities. A representation item applies to an entity identified by a @fa, which denotes an entity declared local to the current declarative region, or a library unit declared immediately preceding a representation pragma in a @fa. @dby There are four kinds of @i: @fas for representation attributes, @fas, @fas, and @i. Representation items specify how the types and other entities of the language are to be mapped onto the underlying machine. They can be provided to give more efficient representation or to interface with features that are outside the domain of the language (for example, peripheral hardware). An @fa for an operational attribute is an @i. Operational items specify other specifiable properties of entities. An operational item or a representation item applies to an entity identified by a @fa, which denotes an entity declared local to the current declarative region, or a library unit declared immediately preceding a representation pragma in a @fa. !corrigendum 13.01(02) @drepl @xcode<@fa> @dby @xcode<@fa> !corrigendum 13.01(04) @drepl @xindent or @fa is allowed.> @dby @xindent, @fa, or @fa is allowed.> !corrigendum 13.01(05) @drepl In a representation item, if the @fa is a @fa, then it shall resolve to denote a declaration (or, in the case of a @fa, one or more declarations) that occurs immediately within the same @fa as the representation item. If the @fa has an @fa, then it shall resolve to denote an implementation-defined component (see 13.5.1) or a class-wide type implicitly declared immediately within the same @fa as the representation item. A @fa that is a @fa<@i_name> (only permitted in a representation pragma) shall resolve to denote the @fa that immediately precedes (except for other pragmas) the representation pragma. @dby In an operational item or representation item, if the @fa is a @fa, then it shall resolve to denote a declaration (or, in the case of a @fa, one or more declarations) that occurs immediately within the same @fa as the item. If the @fa has an @fa, then it shall resolve to denote an implementation-defined component (see 13.5.1) or a class-wide type implicitly declared immediately within the same @fa as the item. A @fa that is a @fa<@i_name> (only permitted in a representation pragma) shall resolve to denote the @fa that immediately precedes (except for other pragmas) the representation pragma. !corrigendum 13.01(06) @drepl The @fa of a @fa or representation pragma shall statically denote an entity (or, in the case of a @fa, one or more entities) declared immediately preceding it in a @fa, or within the same @fa, @fa, @fa, @fa, or @fa as the representation item. If a @fa denotes a local callable entity, it may do so through a local @fa (as a way to resolve ambiguity in the presence of overloading); otherwise, the @fa shall not denote a @fa. @dby The @fa of an @fa or representation pragma shall statically denote an entity (or, in the case of a @fa, one or more entities) declared immediately preceding it in a @fa, or within the same @fa, @fa, @fa, @fa, or @fa as the representation or operational item. If a @fa denotes a local callable entity, it may do so through a local @fa (as a way to resolve ambiguity in the presence of overloading); otherwise, the @fa shall not denote a @fa. !corrigendum 13.01(08) @dinsa A representation item @i an @i of the entity denoted by the @fa, except in the case of a type-related representation item, whose @fa shall denote a first subtype, and which directly specifies an aspect of the subtype's type. A representation item that names a subtype is either @i (Size and Alignment clauses) or @i (all others). Subtype-specific aspects may differ for different subtypes of the same type. @dinst The @fa of an operational item shall denote a first subtype. An operational item @i an @i of the type of the subtype denoted by the @fa. Operational items are type-related. !corrigendum 13.01(09) @dinsa A representation item that directly specifies an aspect of a subtype or type shall appear after the type is completely defined (see 3.11.1), and before the subtype or type is frozen (see 13.14). If a representation item is given that directly specifies an aspect of an entity, then it is illegal to give another representation item that directly specifies the same aspect of the entity. @dinst An operational item that directly specifies an aspect of a type shall appear before the type is frozen (see 13.14). If an operational item is given that directly specifies an aspect of a type, then it is illegal to give another operational item that directly specifies the same aspect of the type. !corrigendum 13.01(11) @drepl Representation aspects of a generic formal parameter are the same as those of the actual. A type-related representation item is not allowed for a descendant of a generic formal untagged type. @dby Operational and representation aspects of a generic formal parameter are the same as those of the actual. A type-related representation item is not allowed for a descendant of a generic formal untagged type. !corrigendum 13.01(19) @drepl For the elaboration of a @fa, any evaluable constructs within it are evaluated. @dby For the elaboration of an @fa, any evaluable constructs within it are evaluated. !corrigendum 13.03(00) @drepl Representation Attributes @dby Operational and Representation Attributes !corrigendum 13.03(01) @drepl The values of certain implementation-dependent characteristics can be obtained by interrogating appropriate representation attributes. Some of these attributes are specifiable via an @fa. @dby The values of certain implementation-dependent characteristics can be obtained by interrogating appropriate operational or representation attributes. Some of these attributes are specifiable via an @fa. !corrigendum 13.03(05) @drepl An @fa is allowed in an @fa only if this International Standard explicitly allows it, or for an implementation-defined attribute if the implementation allows it. Each specifiable attribute constitutes an aspect of representation. @dby An @fa is allowed in an @fa only if this International Standard explicitly allows it, or for an implementation-defined attribute if the implementation allows it. Each specifiable attribute constitutes an operational aspect or an aspect of representation. !corrigendum 13.03(09) @drepl The following attributes are defined: @dby The following representation attributes are defined: !corrigendum 13.03(68) @drepl For a prefix X that denotes an array subtype or array object (after any implicit dereference): @dby For a prefix X that denotes an array subtype or array object (after any implicit dereference), the following representation attribute is defined: !corrigendum 13.03(74) @drepl For every subtype S of a tagged type T (specific or class-wide), the following attribute is defined: @dby For every subtype S of a tagged type T (specific or class-wide), the following operational attribute is defined: !corrigendum 13.11(2) @drepl A storage pool is a variable of a type in the class rooted at Root_Storage_Pool, which is an abstract limited controlled type. By default, the implementation chooses a standard storage pool for each access type. The user may define new pool types, and may override the choice of pool for an access type by specifying Storage_Pool for the type. @dby A storage pool is a variable of a type in the class rooted at Root_Storage_Pool, which is an abstract limited controlled type. By default, the implementation chooses a standard storage pool for each access type. The user may define new pool types, and may override the choice of pool for an access type by specifying the representation attribute Storage_Pool for the type. !corrigendum 13.11(12) @drepl For every access subtype S, the following attributes are defined: @dby For every access subtype S, the following representation attributes are defined: !corrigendum 13.13.2(1) @drepl The Write, Read, Output, and Input attributes convert values to a stream of elements and reconstruct values from a stream. @dby The Write, Read, Output, and Input operational attributes convert values to a stream of elements and reconstruct values from a stream. !corrigendum 13.14(19) @drepl A representation item that directly specifies an aspect of an entity shall appear before the entity is frozen (see 13.1). @dby An operational item or a representation item that directly specifies an aspect of an entity shall appear before the entity is frozen (see 13.1). !ACATS test Create a C-Test to verify that Read/Write attributes can be defined on derived non-tagged types. !appendix !section 13.1(10) !subject Attribute definition clause for Stream Attributes !reference RM95-13.1(10) !reference RM95-13.1(11) !reference RM95-13.13.2(36) !from Anthony Gargaro 96-04-28 !keywords !reference 96-5519.a Anthony Gargaro 96-4-28>> !discussion stream attributes, representation items A consequence of specifying attribute definition clauses for the stream attributes is that the restrictions associated with representation items hamper the use of stream attributes. For example, the following idiom is illegal by 13.1(11). with Ada.Streams; use Ada.Streams; generic type T is private; package Attr_Rep is type NT is new T; procedure Attribute_Write( Stream : access Root_Stream_Type'Class; Item : in NT); -- Illegal use of attribute definition clause for NT'Write use Attribute_Write; end Attr_Rep; package body Attr_Rep is procedure Attribute_Write( Stream : access Root_Stream_Type'Class; Item : in NT) is begin -- Save type information for dispatching Write and then call T'Write(Stream, T(Item)); end Attribute_Write; end Attr_Rep; Since allowing such idioms facilitates reading/writing streams that are architecture neutral, consideration should be given to relaxing the application of 13.1(10,11) to representation-independent attributes. **************************************************************** !section 13.1(10) !subject Attribute definition clause for Stream Attributes !reference RM95-13.1(10) !reference RM95-13.1(11) !reference RM95-13.13.2(36) !keywords stream attributes, representation items !reference 96-5519.a Anthony Gargaro 96-4-28 !keywords stream attributes, representation items !from Norman Cohen 96-04-29 !reference 96-5521.a Norman H. Cohen 96-4-29>> !discussion Interestingly, 13.1(11) does not prohibit the following workaround: with Ada.Streams; use Ada.Streams; generic type T is private; package Attr_Rep is type NT is record Only_Component: T; end record; procedure Attribute_Write( Stream : access Root_Stream_Type'Class; Item : in NT); for NT'Write use Attribute_Write; end Attr_Rep; package body Attr_Rep is procedure Attribute_Write( Stream : access Root_Stream_Type'Class; Item : in NT) is begin -- Save type information for dispatching Write and then call T'Write(Stream, Item.Only_Component); end Attribute_Write; end Attr_Rep; Of course this is a nuisance: NT doesn't inherit T's operations, so one always has to invoke Op(X.Only_Component) instead of Op(X). One can define corresponding operations for type NT manually, but there is no way to allow direct conversions between descendents of NT and types that are truly in the derivation class for T. (One wishes to use NT rather than T in constructing new types, so that the 'Write for the new type invokes NT'Write.) On the one hand, the existence of such a loophole indicates that there is no fundamental problem with the relaxation Anthony suggests. On the other hand, the existence of the loophole may make resolution of the problem a little less of an emergency. **************************************************************** !section 13.1(10) !subject Attribute definition clause for Stream Attributes !reference RM95-13.1(10) !reference RM95-13.1(11) !reference RM95-13.13.2(36) !keywords stream attributes, representation items !reference 96-5519.a Anthony Gargaro 96-4-28 !keywords stream attributes, representation items !reference 96-5521.a Norman H. Cohen 96-4-29 !from Bob Duff !reference 96-5542.a Robert A Duff 96-5-8>> !discussion Norm says: > Interestingly, 13.1(11) does not prohibit the following workaround: > [workaround involving wrapping the type in a record] Right. Another workaround is to simply make the thing a tagged type, since 13.1(11) applies only to untagged types. - Bob **************************************************************** !section 13.1(10) !subject Attribute definition clause for Stream Attributes !reference RM95-13.1(10) !reference RM95-13.1(11) !reference RM95-13.13.2(36) !reference 96-5519.a Anthony Gargaro 96-4-28 !reference 96-5521.a Norman H. Cohen 96-4-29 !reference 96-5542.a Robert A Duff 96-5-8 !from Anthony Gargaro 96-05-10 !reference 96-5546.a Anthony 96-5-10>> !discussion >>Norm says: >> Interestingly, 13.1(11) does not prohibit the following workaround: >> [workaround involving wrapping the type in a record] to which Bob replied: >Right. Another workaround is to simply make the thing a tagged type, >since 13.1(11) applies only to untagged types. In the context of the application where this issue was raised both of these options were considered. Unfortunately, neither seems satisfactory since the useability of the abstraction which is presented to the programmer is compromised. This is because the idiom requires the incremental composition of types to allow arbitrary user-defined types to be associated with "architecture neutral" stream attributes. In the case of wrapping the type (which is used at the moment), there is a useability penalty. The programmer must be aware of the wrapper name when referencing subcomponents of the type and this may become onerous if the composite type contains other composite types. **************************************************************** Notes from Pascal Leroy on the changes to define operational attributes, dated 2000-02-23: While there are many changes, the overall scheme is quite simple: not all attribute_definition_clauses are representation items, some are operational items. Operational items are legal in places where representation items are not (e.g. before a type is complete) but by and large they follow the same rules. One notable difference is that an implementation may decide to reject a representation item that it doesn't like, but not an operational item (with the current wording of the RM, the support of stream attributes is entirely optional, even if you support annex C). Then, for each attribute we have to say whether it's a representation attribute or an operational attribute. **************************************************************** Notes from the editor, dated 2000-03-08 Discussions with Pascal added the following points: It is quite unclear what is the scope of the sentence "The following representation attributes are defined:" in 13.3(9) (which was originally "The following attributes are defined"). Obviously it doesn't cover 13.3(61-65), which is a pragma, not an attribute. But then it seems to cover 13.3(68-73) because of the sentence that start with "For ..." in 13.3(68). At any rate, whoever wrote this part decided that there was enough confusion when reaching 13.3(74) that they specified again that "the following attribute is defined". We have changed 13.3(68) to be consistent with the idea that the scope of that statement stops at 13.3(59). But it might be clearer to change each of the attribute definitions consistently with 13.3(68) and 13.3(74), deleting 13.3(9) completely. The syntax changes are scattered about, but should not change the actual syntax of the language in any way. The reason for the syntax changes is not clear, so I'll explain it here. Ada 95 uses reference to syntax constructs wherever possible. There are several dozen uses of "Representation_Clause", many of which should not apply to operational items. In order to fix this, operational items have to be split out of Representation_Clause, which requires a syntax change. Representation_Clause is used in five places in the Ada 95 grammar (3.8, 3.11, 9.1, and 9.4 (twice). We need to consider the impact of changes in all five places. The most appealing fix is to define the syntax as follows: representation_clause ::= attribute_definition_clause | enumeration_representation_clause | record_representation_clause | at_clause operational_clause ::= attribute_definition_clause and then add operational_clause to 3.11(4) [operational attributes definition clauses only make sense in declarative parts.] However, this grammar is ambiguous, in that there is no way to tell when an attribute definition clause is operational or representational syntactically. Pascal proposed removing attribute_definition_clause from representation_clause, then adding it back where needed. He suggested only adding it to 3.11(4), as that is the primary usage. However, that would prevent the use of attribute definition clauses in protected types (both specification and body), task specifications, and component clauses. While not all of these have useful clauses today, eliminating their use in those places would be a substantial change. Randy (the editor) proposed the following: representation_clause ::= attribute_definition_clause | representation_item_clause representation_item_clause ::= enumeration_representation_clause | record_representation_clause | at_clause This has the advantage of not requiring changes at the uses of representation_clause. However, Pascal though it to be too confusing (that a representation_clause wasn't necessarily a representation clause), and I agreed with him. Therefore, I've changed the grammar to: aspect_clause ::= attribute_definition_clause | representation_clause representation_clause ::= enumeration_representation_clause | record_representation_clause | at_clause and modified all 5 uses. This version allows use to use "aspect_clause" rather than "representation_clause and attribute_definition_clause" wherever some rule applies to both representation and operational aspects. One alternative would be to avoid the syntax changes altogether by saying "representation_clauses except operational items" at the appropriate points. But that seems to confuse the issue. Note that the changes listed here don't include the corresponding changes in the (non-normative) syntax summary. I'll do this in the integrated reference manual, of course, but doing it here just bulks this up further. ****************************************************************