!standard 13.13.1 (00) 01-08-31 AI95-00195/08 !class binding interpretation 98-03-27 !status work item 98-04-04 !status received 98-03-27 !reference AI95-00108 !reference AI95-00145 !priority High !difficulty Hard !subject Streams !summary 1 - When the predefined Input attribute creates an object, this object undergoes default initialization and finalization. 2 - For the purposes of checking legality rules, it is necessary to determine whether a stream-oriented attribute has been specified for a limited type (13.13.2(36)). This is done by applying the normal visibility rules to the attribute_definition_clause. 3 - For a limited tagged type T, if Read is available then T'Input is available, even if it is not specified. Similarly, if Write is available then T'Output is available. T'Class'Read, T'Class'Write, T'Class'Input and T'Class'Output are not available unless they are specified. 4 - In the profiles of the stream-oriented attributes, the notation "italicized T" refers to the base subtype for a scalar type, and to the first subtype otherwise. 5 - In an attribute_definition_clause for a stream-oriented attribute, the name shall not denote an abstract subprogram. 6 - The predefined Read attribute for composite types with defaulted discriminants must ensure that, if exceptions are raised by the Read attribute for some discriminant, the discriminants of the actual object passed to Read are not modified. This may require the creation of an anonymous object, which undergoes initialization and finalization. 7 -The predefined Read attribute for composite types with defaulted discriminants must raise Constraint_Error if the discriminants found in the stream differ from those of the actual parameter to Read, and this parameter is constrained. 8 - If S is a subtype of an abstract type, an attribute_reference for S'Input is illegal unless this attribute has been specified by an attribute_definition_clause. 9 - The number of calls performed by the predefined implementation of the stream-oriented attributes on the Read and Write operations of the stream type is unspecified. An implementation may take advantage of this permission to perform internal buffering. However, all the calls on the Read and Write operations of the stream type needed to implement an explicit invocation of a stream-oriented attribute must take place before this invocation returns. !question 1 - 13.13.2(27) states that S'Input "creates an object (with the bounds or discriminants, if any, taken from the stream), initializes it with S'Read, and returns the value of the object." Does the verb "initialize" in this sentence refer to the entire initialization process mentioned in 3.3.1(18) and 7.6(10)? (Yes.) In particular, if S is a controlled subtype, or if it contains controlled components, is the Initialize subprogram called? (Yes.) Is the Finalize subprogram called when the intermediate object is finalized? (Yes.) For a record type whose components have initial values, are these values evaluated? (Yes.) 2 - 13.13.2(36) states that "an attribute_reference for one of these attributes is illegal if the type is limited, unless the attribute has been specified by an attribute definition clause." If some stream-oriented attribute has been specified in a private part, and we are at a point that doesn't have visibility over that private part, is a reference to the attribute legal? (No.) 3 - Let T be a limited type with an attribute_definition_clause for attribute Read. Is a usage of T'Class'Read legal? (Yes.) 4 - The definition of the profiles of S'Read, S'Write, S'Input and S'Output given in 13.13.2 uses the notation "italicized T" for the type of the Item parameter. What is the meaning of "italicized T" in this context? (T'Base for scalars, first subtype otherwise.) 5 - In an attribute_definition_clause for a stream attribute, is it legal to give a name that denotes an abstract subprogram? (No.) 6 - 13.13.2(9) states that for a record type, the predefined S'Read reads the components in positional aggregate order. However, the language doesn't seem to specify what happens when exceptions are raised by the calls to the Read attribute for the components. Consider for example the following type declarations: type T1 is range ...; type T2 is range ...; type R (D1 : T1 := ...; D2 : T2 := ...) is record ... end record; Say that attributes_definition_clauses have been given for T1'Read and T2'Read, and consider a call to R'Read. Assume that, during this call, an exception is raised by T2'Read. Is the discriminant X.D1 modified? (No.) 7 - Consider a call to T'Read where T is a type with defaulted discriminants. If the discriminants found in the stream have values different from those of the discriminants of the object passed to T'Read for the Item parameter, and that object is constrained, is Constraint_Error raised? (Yes.) 8 - If T is an abstract type, is the function T'Input abstract? (No, but it cannot be called.) 9 - 13.13.1(1) states that "T'Read and T'Write make dispatching calls on the Read and Write procedures of the type Root_Stream_Type." Is the number of those calls specified? (No.) !recommendation (See Summary.) !wording (See Corrigendum.) !discussion 1 - It seems logical to make Input follow as closely as possible the semantics of code that could be written by a user, so the implementation of S'Input should obtain the discriminants or bounds from the stream, and then declare an object with appropriate discriminants or bounds, as in: declare Anon : S (); begin S'Read (..., Anon); end; Accordingly, the initialization described in 3.3.1(8-9) and 7.6(10) takes place when Anon is declared, and the finalization described in 7.6.1 takes place when Anon disappears (and before returning from the call to S'Input). Note that as part of initialization, compiler-specific fields are initialized as required by the implementation (and as permitted by AARM 3.3.1(14.a)). 2 - Consider for example: package P is type T is limited private; private type T is new Boolean; procedure Read (Stream : ...; Item : out T); for T'Read use Read; end P; with P; procedure Q is X : P.T; begin P.T'Read (..., X); -- Illegal? end Q; The call to P.T'Read is illegal, because Q doesn't have visibility over the private part of P, which contains the attribute_definition_clause for attribute Read. On the other hand, at a place that has visibility over the private part of P (and that comes after the attribute_definition_clause) a reference to T'Read is legal. This rule is necessary to preserve the privacy of private types. Note that it is the location of the attribute_definition_clause that counts, not that of the subprogram specified in that clause. Thus, if the procedure Read above were moved to the visible part of P, a reference to P.T'Read would still be illegal (but a reference to P.Read wouldn't). Because the stream attributes are operational attributes (13.13.2(1/1)), an attribute_definition_clause may be given before the type is fully defined. 3 - In order to simplify the discussion, we first define a new term: a stream- oriented attribute is "available" at some place in the program text if an attribute_reference for that attribute is (or would be) legal at that place. The rules given in 13.13.2(9/1) try to insure that if the Read attribute is available for a limited tagged ancestor type, then it as also available for all of the types derived from that ancestor. However, this is not true because this rule fails to take into account the visibility issues mentioned in item #2 above. Consider for example: package P is type T is tagged limited private; private type T is new Boolean; for T'Read use ... end P; with P; package Q is protected type Prot is ... end Prot; type NT is new T with record C : Prot; end record; -- No need to define Read (13.13.2(9/1)) end Q; with Q; package body P is type NNT is new NT with null record; ... NNT'Read (...); -- Legal? end P; Because the attribute_definition_clause for P.T'Read is not visible at the place where NT is declared, 13.13.2(9/1) does not apply, and it is therefore not necessary to define the Read attribute for Q.NT. However, when we come to the declaration of NNT, we want to ensure that NNT is not callable, because we have no mechanism for reading the component C. Instead of depending on whether the attribute has been specified for some ancestor type, 13.13.2(36/1) must depend on whether the attribute is available for the parent type (and for the types of the extension components). Moreover, dispatching to the Read attribute does not work: there is no guarantee that all the types derived from T will have an available Read attribute. So the attribute Read is not available for T'Class. The default implementation of T'Input is defined in terms of T'Read. If T'Read is available, then the implementation of T'Input is well-defined as well, and there is no reason to prohibit calls. A similar argument applies to T'Output when T'Write is available. But T'Class'Input and T'Class'Output are both unavailable. The above model is unfortunately not what is stated by the rules in 13.13.2(36/1). These rules seem to imply that a reference to Input (resp. Output) is legal for the type extension if Input (resp. Output) is available for the parent type. This is incorrect because the default implementation of Input and Output calls Read or Write for the same type, not Input or Output for the parent type. It should say that a reference to Input (resp. Output) is legal for the type extension if Read (resp. Write) is available for that type. Given that the class-wide stream attributes cannot be available for limited tagged types, the last sentence of 13.13.2(9/1) becomes useless, and might as well be removed. 4 - AI95-00145 specifies the meaning of the notation "italicized T" for operators as follows: "The italicized T shown in the definitions of predefined operators means: - T'Base, for scalars - the first subtype, for tagged types - the type without any constraint, in other cases" In the case of stream-oriented attributes the notation "italicized T" must be consistent with the parameter subtype required for attribute_definition_clauses. If we chose the same rule as for operators, we would have a discrepancy in the case of constrained untagged types, and this would unnecessarily complicate the static and dynamic semantics. When one of the stream-oriented attributes is specified by an attribute definition clause, 13.13.2(36) states that "the subtype of the Item parameter shall be the base subtype if scalar, and the first subtype otherwise." Therefore, in the parameter profiles for the stream-oriented attributes in section 13.13, the notation "italicized T" means: - T'Base, for scalars - the first subtype, in other cases 5 - Obviously it should not be possible to perform a non-dispatching call to an abstract subprogram (stream-oriented attributes are always called in a non-dispatching manner). Therefore, we have two options: - Make the attribute_definition_clause illegal. - Make the calls (explicit or implicit) illegal. The second option is a significant implementation burden, and allowing the attribute_definition_clause only to reject all calls doesn't seem to do any good. That's why the first option was preferred. 6 - The problem mentioned in the question only exists for a type R that is passed by-reference to R'Read: obviously if the type is passed by copy, an exception raised by R'Read cannot affect the original object. In the case of a type which is passed by-reference, we must consider two cases: - If the exception in T2'Read is due to the failure of some language-defined check, 11.6(6) explains that the object or its parts may become abnormal, so we don't have to specify what happens to the discriminants. - If the exception in T2'Read is due to an explicit raise, the object obviously doesn't become abnormal, and therefore we must preserve the integrity of its discriminants. In other words, either all discriminants are updated (if the calls to the Read attributes for the discriminants were successful) or none (if any call to a Read attribute for a discriminant raised an exception). This model requires an implementation to read the discriminants, create an anonymous object using the given discriminants and assign that object to the formal parameter Item. The normal initialization and finalization take place for this anonymous object. Strictly speaking, the use of an anonymous object is only required for a type with defaulted discriminants which is passed by-reference, if the actual parameter of Read is not constrained. However, an implementation is free to use anonymous objects in other cases. Use of an anonymous object is only required for discriminants. An implementation is free to read the other components directly in the Item parameter. For example, if we change the original example as follows: type R is record C1 : T1; C2 : T2; end record; then if T2'Read raises an exception when reading component C2, it is unspecified if C1 is modified or not. 7 - When the type has defaulted discriminants, the predefined Read attribute must read them from the stream. It can be the case that the actual object passed to Read is constrained. In this case, the discriminants found in the stream may or may not match those of the actual. If they don't match, Constraint_Error is raised, and this is a Discriminant_Check. It is unspecified whether this effect is achieved by assigning a temporary object, as explained in #6 above, or by other means. 8 - If T is an abstract type, calling the function T'Input would effectively create an object whose tag designates T, which is absurd. We could decide that T'Input is abstract, but it seems simpler to say that any attribute_reference for this attribute is illegal, by analogy with the rule stated in 13.13.2(36) for limited types. 9 - Surely the user could count the calls to the Read and Write operations for the stream type by writing a perverse implementation of these operations, but it seems that performance should have precedence: for the predefined implementation of String'Write, requiring a call to Ada.Streams.Write for each character would be a big performance hit, with no real benefits. Therefore, the number of calls to the Read and Write operations is unspecified, and implementations are free (and in fact advised) to do internal buffering. However, we don't want to allow an implementation to buffer all stream output and do only one call to Write when the program terminates: the user must be able to assume reasonable properties regarding the underlying buffering mechanism. That's why we require that all the calls to Read or Write take place before the top-level call to a stream-oriented attribute completes. In other words, an implementation may combine several consecutive calls to Write into a single one, provided these calls all pertain to a single top-level call to the attribute Write (or Output). !corrigendum 13.13.2(1/1) @dinsa The operational attributes Write, Read, Output, and Input convert values to a stream of elements and reconstruct values from a stream. @dinst The subtype of the Item parameter of the stream-oriented attributes is the base subtype of @i if @i is a scalar type, and the first subtype otherwise. The same rule applies to the result of the Input attribute. !corrigendum 13.13.2(9/1) @drepl For elementary types, the representation in terms of stream elements is implementation defined. For composite types, the Write or Read attribute for each component is called in canonical order, which is last dimension varying fastest for an array, and positional aggregate order for a record. Bounds are not included in the stream if @i is an array type. If @i is a discriminated type, discriminants are included only if they have defaults. If @i is a tagged type, the tag is not included. For type extensions, the Write or Read attribute for the parent type is called, followed by the Write or Read attribute of each component of the extension part, in canonical order. For a limited type extension, if the attribute of any ancestor type of @i has been directly specified and the attribute of any ancestor type of the type of any of the extension components which are of a limited type has not been specified, the attribute of @i shall be directly specified. @dby For elementary types, the representation in terms of stream elements is implementation defined. For composite types, the Write or Read attribute for each component is called in canonical order, which is last dimension varying fastest for an array, and positional aggregate order for a record. Bounds are not included in the stream if @i is an array type. If @i is a discriminated type, discriminants are included only if they have defaults. If @i is a tagged type, the tag is not included. For type extensions, the Write or Read attribute for the parent type is called, followed by the Write or Read attribute of each component of the extension part, in canonical order. !corrigendum 13.13.2(27) @drepl S'Output then calls S'Write to write the value of Item to the stream. S'Input then creates an object (with the bounds or discriminants, if any, taken from the stream), initializes it with S'Read, and returns the value of the object. @dby S'Output then calls S'Write to write the value of Item to the stream. S'Input then creates an object (with the bounds or discriminants, if any, taken from the stream), initializes it with S'Read, and returns the value of the object. The normal initialization and finalization take place for this object (see 3.3.1, 7.6, 7.6.1). !corrigendum 13.13.2(35) @drepl In the default implementation of Read and Input for a composite type, for each scalar component that is a discriminant or whose @fa includes a @fa, a check is made that the value returned by Read for the component belongs to its subtype. Constraint_Error is raised if this check fails. For other scalar components, no check is made. For each component that is of an access type, if the implementation can detect that the value returned by Read for the component is not a value of its subtype, Constraint_Error is raised. If the value is not a value of its subtype and this error is not detected, the component has an abnormal value, and erroneous execution can result (see 13.9.1). @dby In the default implementation of Read and Input for a composite type, for each scalar component that is a discriminant or whose @fa includes a @fa, a check is made that the value returned by Read for the component belongs to its subtype. Constraint_Error is raised if this check fails. For other scalar components, no check is made. For each component that is of an access type, if the implementation can detect that the value returned by Read for the component is not a value of its subtype, Constraint_Error is raised. If the value is not a value of its subtype and this error is not detected, the component has an abnormal value, and erroneous execution can result (see 13.9.1). In the default implementation of Read for a composite type with defaulted discriminants, if the actual parameter of Read is constrained, a check is made that the discriminants read from the stream are equal to those of the actual parameter. Constraint_Error is raised if this check fails. If Constraint_Error is raised during a call on Read because of failure of one the above checks, the implementation must ensure that the discriminants of the actual parameter of Read are not modified. It is unspecified how this effect is achieved. !corrigendum 13.13.2(36/1) @drepl The stream-oriented attributes may be specified for any type via an @fa. All nonlimited types have default implementations for these operations. An @fa for one of these attributes is illegal if the type is limited, unless the attribute has been specified by an @fa or (for a type extension) the attribute has been specified for an ancestor type. For an @fa specifying one of these attributes, the subtype of the Item parameter shall be the base subtype if scalar, and the first subtype otherwise. The same rule applies to the result of the Input function. @dby The stream-oriented attributes may be specified for any type via an @fa. The subprogram name given in such a clause shall not denote an abstract subprogram. A stream-oriented attribute for a subtype of a specific type @i is @i at places where one of the following conditions is true: @xbullet is nonlimited.> @xbullet is nonlimited and not abstract.> @xbullet is a limited type extension, and the attribute Read (resp Write) is available for the parent type of @i and for the types of all of the extension components.> @xbullet is a limited type, and the attribute Read (resp. Write) is available for @i.> @xbullet, and the @fa is visible. A stream-oriented attribute for a subtype of a class-wide type T'Class is available at places where one of the following conditions is true: @xbullet<@i is nonlimited.> @xbullet, and the @fa is visible.> An @fa for one of the stream attributes is illegal unless the attribute is available at the place of the @fa. For an @fa specifying one of these attributes, the subtype of the Item parameter shall be the base subtype if scalar, and the first subtype otherwise. The same rule applies to the result of the Input function. !corrigendum 13.13.2(36.1/1) @dinsa For every subtype @i of a language-defined nonlimited specific type @i, the output generated by S'Output or S'Write shall be readable by S'Input or S'Read, respectively. This rule applies across partitions if the implementation conforms to the Distributed Systems Annex. @dinst @i<@s8>@hr The number of calls performed by the predefined implementation of the stream- oriented attributes on the Read and Write operations of the stream type is unspecified. An implementation may take advantage of this permission to perform internal buffering. However, all the calls on the Read and Write operations of the stream type needed to implement an explicit invocation of a stream-oriented attribute must take place before this invocation returns. An explicit invocation is one appearing explicitly in the program text, possibly through a generic instantiation (see 12.3). !appendix !section 13.13.1 !subject Various issues with the stream-oriented attributes !reference RM95 13.13.1 !reference RM95 13.13.2 !reference AI95-00108 !from Pascal Leroy 97-09-02 !reference 1997-15783.a Pascal Leroy 1997-9-2>> !discussion 1 - RM95 13.13.2(27) states that S'Input "creates an object (with the bounds or discriminants, if any, taken from the stream), initializes it with S'Read, and returns the value of the object. Does the verb "initialize" in this sentence refer to the entire initialization process mentioned in RM95 3.3.1(18) and 7.6(10)? In particular, if S is a controlled subtype, or if it contains controlled components, is the Initialize subprogram called? Is the Finalize subprogram called when the intermediate object is finalized? For a record type whose components have initial values, are these values evaluated? It seems that the simplest model is that S'Input declares a local object, which is then passed to S'Read, as in: X : S (); begin S'Read (..., X); If we don't do that, the object passed to S'Read might have uninitialized access values, or uninitialized compiler-specific fields (dopes, offsets, tag, etc.). 2 - RM95 13.13.2(36) states that "an attribute_reference for one of these attributes is illegal if the type is limited, unless the attribute has been specified by an attribute definition clause." If some stream-oriented attribute has been specified in a private part, and we are at a point that doesn't have visibility over that private part, is a reference to the attribute legal? For example: package P is type T is limited private; private procedure Read (Stream : ...; Item : out T); for T'Read use Read; end P; with P; procedure Q is X : T; begin T'Read (..., X); -- Legal? end Q; One hopes that the call to T'Read is illegal, overwise it would break the privacy of private types. 3 - Let T a limited type with an attribute_definition_clause for attribute Read, and D a type derived from T, and assume that there is no attribute definition clause for D'Read: type T is limited record ... end record; for T'Read use ...; type D is new T; Is a usage of D'Read legal or not? In other words, shall we consider that, for the purpose of checking RM95 13.13.2(36), "an attribute has been specified" for D? If the answer is "yes", how do the inheritance rules stated in AI95-00108 apply in the case where T is tagged, and D has a component of a task type in its record extension part? How is an implementation expected to read that component? 4 - The definition of the profiles of the predefined S'Read, S'Write, S'Input and S'Read given in RM95 13.13.2 uses the notation "T italic" for the type of the Item parameter. AI95-00145 explains that: "The italicized T shown in the definitions of predefined operators means: - T'Base, for scalars - the first subtype, for tagged types - the type without any constraint, in other cases" (Note that the above sentence says "operators", so strictly speaking it doesn't apply to attributes; it seems that the wording of this AI should be broadened.) When one of these attributes is specified by an attribute definition clause, RM95 13.13.2(36) states that "the subtype of the Item parameter shall be the base subtype if scalar, and the first subtype otherwise." There is a problem because these definitions don't coincide in the case of constrained array types. Consider: type T is new String (1 .. 10); It appears that the type of the Item parameter of the predefined stream-oriented attributes is "T without any constraint" (an anonymous unconstrained array type ), while the type of the Item parameter for a user-defined stream-oriented subprogram is T. In particular, does the presence or absence of an attribute definition clause have any bearing on the legality of the calls? For example, consider the legality of the 'others' choice in an array aggregate; it depends on the existence on an applicable index constraint, and therefore on whether the type of the parameter is constrained or not: package P is type T is new String (1 .. 10); procedure Write (...; Item : in T); private for T'Write use Write; end P; with P; procedure Q is begin T'Write (..., (others => 'a')); -- Legal? end; Is the above call legal? If yes, would it become illegal if the attribute_definition_clause were removed? A possible model is to say that an attribute_definition_clause changes the body of the Read attribute, but not its profile. It's as if the predefined Read was just a wrapper calling the user-specified subprogram. 5 - AI95-00108 states (in the !discussion section) that "for untagged derived types, there is no problem for the derived type inheriting the stream attributes." This doesn't seem clear if the derived type includes a known discriminant part. Consider: type Parent (D1, D2 : Integer := 1) is ...; type Child (D : Integer := 2) is new Parent (D1 => D, D2 => D); Clearly Parent'Write writes two discriminant values. It would seem that Child'Write should only write one discriminant value, which contradicts the simple inheritance rule given in the AI. 6 - RM95 13.13.2(9) states that for a record type, the predefined S'Read reads the components in positional aggregate order. However, the RM95 doesn't seem to specify what happens when exceptions are raised by the calls to the Read attribute for the components. Consider for example the following type declarations: type T1 is range ...; type T2 is range ...; type R (D1 : T1 := ...; D2 : T2 := ...) is record ... end record; Say that attributes_definition_clauses have been given for T1'Read and T2'Read, and consider the call: X : R; ... R'Read (..., X); Assume that an exception is raised by T2'Read. Is the discriminant X.D1 modified? That would be unpleasant if there were components depending on this discriminant! Consider a different example, where there are no discriminants: type T1 is ...; type T2 is ...; type R is record C1 : T1; C2 : T2; end record; Assume that an exception is raised by T2'Read. Is the component X.C1 modified? It would seem that we should stick to the notion that discriminants are only modified by an assignment of entire objects. This probably requires an intermediate object in the case of discriminated types. However, it would seem quite expensive to require the creation of such an intermediate object for types that don't have discriminants. Note that if we adopt the idea that an intermediate object is needed (at least in some cases) then we must define if initialization and finalization of this object take place. 7 - Consider a call to T'Read where T is a type with defaulted discriminants. If the discriminants found in the stream have values different from those of the discriminants of the object passed to T'Read for the Item parameter, and that object is constrained, is Constraint_Error raised? Note that if we adopt the model that an intermediate object is needed in this case, then the constraint check performed when assigning the intermediate object to the actual parameter will raise Constraint_Error. 8 - If T is an abstract type, is the function T'Input abstract? One hopes so, otherwise it makes it possible to create objects of an abstract type. 9 - RM95 13.13.1(1) states that "T'Read and T'Write make dispatching calls on the Read and Write procedures of the type Root_Stream_Type." Is the number of those calls specified? For example, for the predefined implementation of String'Write, is an implementation required to call Ada.Streams.Write for each character? or is it allowed to perform internal buffering and to call Ada.Streams.Write only once for the entire string? Obviously the user could tell the difference by writing a pervert implementation of the Write subprogram, but it would seem that performance considerations should have the priority in this case. _____________________________________________________________________ Pascal Leroy +33.1.30.12.09.68 pleroy@rational.com +33.1.30.12.09.66 FAX **************************************************************** From: Tucker Taft Sent: Friday, February 26, 1999 9:47 AM Subject: Re: Updated AIs AI 195 does not address an issue that we have confronted recently relating to stream attributes. It is very difficult to specify stream attributes for a limited private type, if you require them to be specified in the visible part. In general, you may not specify a "representation" attribute until after a type is fully defined. But if you also have to specify stream attributes in the visible part to make them usable, then you have a contradiction. There seem to be two solutions. One is to allow stream attributes to be specified before the type is fully defined. The other is to allow them to be specified in the private part. I suppose another option is to have some kind of "incomplete" stream attribute specification, such as "for Lim_Type'Read use <>;" in the visible part, and then complete the definition in the private part. This is rampant invention, of course, but it solves another problem. Types like Exception_Occurrence are required to have stream attributes, but not have any other primitive operations declared in the visible part. However stream attributes can only be defined in terms of some "normal" subprogram, which must necessarily also be visible at the point of the stream attribute definition. Another contradiction... > The update to AI > 195 is partial: I believe that Tucker owns the part of this AI that has to do > with the number of stream elements written/read for a scalar type. Okay, I will handle that part. -Tuck **************************************************************** From: Pascal Leroy Sent: Monday, March 01, 1999 4:14 AM > There seem to be two solutions. One > is to allow stream attributes to be specified before the > type is fully defined. The other is to allow them to be specified > in the private part. I hate to open private parts. In our compiler, this is a real nightmare (we have to do that for pragma Convention, and that's already a big pain in the neck). So my preference would be to allow the specification of stream attributes before the type is fully defined. Remember that we already have an AI that says that 13.1(10) does not apply to stream attributes. This would just be another oddity with stream-oriented attributes. (In fact I believe the stream-oriented attributes should not be considered a representation item, since they do not affect the physical representation of the type; they should be "something else", with much more relaxed rules; but we are not going to rewrite chapter 13...) > I suppose another option is to have some > kind of "incomplete" stream attribute specification, > such as "for Lim_Type'Read use <>;" in the visible part, > and then complete the definition in the private part. This is > rampant invention, of course, but it solves another problem. This would have been a nice idea in '93, but at this point I think the language is insufficiently broken to invent new syntax. > Types like Exception_Occurrence are required to have stream attributes, > but not have any other primitive operations declared in the > visible part. However stream attributes can only be defined > in terms of some "normal" subprogram, which must necessarily also > be visible at the point of the stream attribute definition. > Another contradiction... If there is a problem with this package, then I'd rather see the ARG modify the specification of Ada.Exceptions to include the additional stuff needed for streaming, rather than adding new syntax for this cornercase. Pascal **************************************************************** From: Tucker Taft Sent: Monday, March 01, 1999 8:18 AM > > There seem to be two solutions. One > > is to allow stream attributes to be specified before the > > type is fully defined. The other is to allow them to be specified > > in the private part. > > I hate to open private parts. In our compiler, this is a real nightmare (we > have to do that for pragma Convention, and that's already a big pain in the > neck). > > So my preference would be to allow the specification of stream attributes > before the type is fully defined. Remember that we already have an AI that > says that 13.1(10) does not apply to stream attributes. This would just be > another oddity with stream-oriented attributes. (In fact I believe the > stream-oriented attributes should not be considered a representation item, > since they do not affect the physical representation of the type; they should > be "something else", with much more relaxed rules; but we are not going to > rewrite chapter 13...) Yes, I agree, since 13.1(10) does not apply to stream attributes, we should view them as a special category of attribute, and allow them to be specified on private types and other not-yet-completely-defined types. > > I suppose another option is to have some > > kind of "incomplete" stream attribute specification, > > such as "for Lim_Type'Read use <>;" in the visible part, > > and then complete the definition in the private part. This is > > rampant invention, of course, but it solves another problem. > > This would have been a nice idea in '93, but at this point I think the > language is insufficiently broken to invent new syntax. > > > Types like Exception_Occurrence are required to have stream attributes, > > but not have any other primitive operations declared in the > > visible part. However stream attributes can only be defined > > in terms of some "normal" subprogram, which must necessarily also > > be visible at the point of the stream attribute definition. > > Another contradiction... > > If there is a problem with this package, then I'd rather see the ARG modify > the specification of Ada.Exceptions to include the additional stuff needed for > streaming, rather than adding new syntax for this cornercase. If we allow specification of stream attributes on private types, that will probably simplify the solution enough to not justify adding any declarations to Ada.Exceptions. **************************************************************** From: Tucker Taft Sent: Thursday, June 01, 2000 9:25 PM ... I would suggest that Output and Input piggy back automatically on Write and Read, even for limited types: If the Read attribute of a type can legally be called, then the Input attribute has a non-abstract default implementation; similarly, if the Write attribute of a type can legally be called, then the Output attribute has a non-abstract default implementation. **************************************************************** From: Randy Brukardt Sent: Friday, June 02, 2000 5:12 PM This seems like a good idea, but it's going well beyond the AI, or even what is currently in AI-00195. I don't want to bog the corrigendum down at the last minute with good ideas... I suggest that we add that to AI-195. Clearly, this wouldn't conflict with the current wording (which defines that these always use the default implementation, but leaves them uncallable for limited types). But I'm not sure it is useful for the implementation burden -- Input is a function after all, and limited functions aren't very useful. **************************************************************** Editor's note, 7/7/2000 Original questions 3 & 5 were deleted, as they have been handled in the corrigendum wording for AI-108. I also added Tucker's suggestion to the AI as question 3, and moved up question 11 to take the space of question 5. **************************************************************** Editor's note, 5/25/2001 The stream size stuff was moved to a new AI (AI-270), as suggested by the ARG at the recent meeting in Leuven. **************************************************************** From: Pascal Leory Sent: Friday, August 3, 2001 3:47 AM I am looking at the rules for streaming of limited types in TC1 (specifically in DR 0040), and it seems to me that they are not quite correct. (We never seem to get streams right, no matter how hard or how often we try.) In 13.13.2(9/1), a section pertaining to Read and Write, we have: "For a limited type extension, if the attribute of any ancestor type of T has been directly specified and the attribute of any ancestor type of the type of any of the extension components which are of a limited type has not been specified, the attribute of T shall be directly specified." In 13.13.2(36/1), a section pertaining to all stream attributes: "An attribute_reference for one of these attributes is illegal if the type is limited, unless the attribute has been specified by an attribute_definition_clause or [(for a type extension)] the attribute has been specified for an ancestor type." I understand that for Read and Write, these rules ensure that the attribute is either (1) not callable or (2) complete in the sense that it deals with all the components, including the limited ones. However, the rules don't seem to work well for Input and Output. Consider the following example: type T1 is tagged limited record ... end record; for T1'Output use ... -- Note: no user-defined T1'Write protected type P is ... end P; type T2 is new T1 with record C : P; end record; T2'Output (...); -- Legal? 13.13.2(36/1) seems to say that the reference to T2'Output is legal because T1'Output was specified. 13.13.2(9/1) is not applicable because the attribute in question is not Read or Write, so apparently the type extension is legal. One is left wondering what T2'Output does at execution. Its default implementation is supposed to write the discriminants and then call T2'Write and P'Write. But in this instance there is no T2'Write and no P'Write, so we have a problem. At any rate, the existence of T1'Output is totally irrelevant, since T2'Output is never defined in terms of T1'Output. It seems that 13.13.2(36/1) needs revision. For Input and Output, a reference should be legal iff Read or Write, resp., have been specified for some ancestor. **************************************************************** From: Randy Brukardt Sent: Thursday, August 16, 2001 4:09 PM Tucker had proposed such a rule only a few days before the Potsdam meeting to finalize the Corrigendum. I made an executive decision to postpone that (lest we introduce still more errors), in part because I was not aware of a technical problem with the proposed rules. (Tuck's proposal was to increase consistency, not to fix a bug.) Anyway, I put this proposal as question 3 in the giant stream AI-195. So I think we can handle the correction there. Conveniently, Pascal is the author of that AI (now that the stream size stuff is out of it, we might even be able to finish it). So I recommend that he add this problem to the AI, then put it on the agenda for the meeting. (How's that for passing the buck? :-) ****************************************************************