!standard 03.09.01 (03) 96-07-23 AI95-00115/00 !standard 07.06(04) !standard A(00) !class confirmation 96-04-04 !status WG9 approved 96-12-07 !status ARG approved 7-0-1 96-06-17 !status work item 96-04-04 !status received 96-04-04 !priority High !difficulty Medium !subject Controlled types in language-defined generic packages !summary 96-04-04 A language-defined generic package may be instantiated at any nesting depth. !question 96-04-04 May an implementation declare a controlled type in its implementation of a language-defined generic package? (No.) For example, may Ada.Sequential_IO.File_Type be a controlled type? (No.) !response 96-04-04 A language-defined generic package may be instantiated at any nesting depth. This follows from the fact that the RM does not say otherwise. This implies that the implementation of a language-defined generic package cannot contain the declaration of a controlled type, since the accessibility rules require that controlled types be declared at library level. If an implementation wishes to implement, say, Ada.Sequential_IO.File_Type in terms of a controlled type, it can declare the controlled type in a separate (non-generic) package, such as System.File_Implementation, and make type File_Type have a component whose type is the controlled type. The implementation model given in A.5.2(46.a), which calls for making the Generator type of the random number packages a controlled type, is wrong. It should instead call for Generator to have a component of a controlled type, declared in a (non-generic) package. !appendix 96-04-04 !section 3.9.1(03) !subject Controlled types in language-defined generic packages !reference RM95-3.9.1(3) !reference RM95-7.6 !reference RM95-A.8.1 !reference RM95-A.8.4 !reference RM95-A.10.1 !reference AARM95-A.5.2(46.a) !from Keith Thompson 95-11-15 !reference 95-5386.a Keith Thompson 95-11-15>> !discussion It's tempting to implement the type File_Type in the various I/O packages as a controlled type, with a Finalize routine that closes the file. Unfortunately, such an implementation would mean that Ada.Sequential_IO and Ada.Direct_IO can only be instantiated at the library level, a serious (and undocumented) incompatibility with Ada 83. I can't find any wording in the RM that forbids such an implementation. To avoid incompatibilities with Ada 83, it would actually be necessary to forbid any language-defined generic package (or at least any of the ones that exist in Ada 83) to contain the declaration of a record extension, either in its specification or in its body. Any such declaration would restrict the places at which such a package can be instantiated. The affected generic packages that present problems for Ada 83 are: Ada.Text_IO.Integer_IO Ada.Text_IO.Float_IO Ada.Text_IO.Fixed_IO Ada.Text_IO.Enumeration_IO Ada.Sequential_IO Ada.Direct_IO For the sake of consistency, the following generic packages should also be considered: Ada.Text_IO.Modular_IO Ada.Text_IO.Decimal_IO Ada.Text_IO.Complex_IO Ada.Text_IO.Pictures.Edited_Output Ada.Storage_IO Ada.Numerics.Generic_Elementary_Functions Ada.Numerics.Generic_Complex_Types Ada.Numerics.Generic_Complex_Elementary_Functions Ada.Numerics.Discrete_Random Ada.Strings.Bounded.Generic_Bounded_Length Ada.Strings.Wide_Bounded.Generic_Bounded_Length Ada.Task_Attributes plus all of the Wide_Text_IO equivalents of the above Text_IO packages. (I *think* these lists are complete, but I won't guarantee it.) Note, however, that implementations are advised to implement Ada.Numerics.Discrete_Random.Generator as a controlled type. If restrictions are imposed on declaring controlled types (or, more generally, record extensions) in language-defined generic packages, it actually shouldn't be too much of a burden on implementers. For example, the type Ada.Sequential_IO.File_Type, or even Ada.Numerics.Discrete_Random.Generator, could be declared as a record containing a component of a controlled type declared in an implementation-defined library package. (The "!reference" headers above are incomplete, since I'm too lazy to track down the RM references for all the packages affected.) **************************************************************** !section 3.9.1(03) !subject Controlled types in language-defined generic packages !reference RM95-3.9.1(3) !reference RM95-7.6 !reference RM95-A.8.1 !reference RM95-A.8.4 !reference RM95-A.10.1 !reference AARM95-A.5.2(46.a) !reference 95-5386.a Keith Thompson 95-11-15 !from Ted Baker 95-11-16 !reference 95-5387.a Ted Baker 95-11-16>> !discussion I ran into similar problems with the library-level only restriction when I used controlled types to implement user-defined task attributes. It occurs to me that a compiler might provide a flag/pragma that would allow implementors of language-defined packages to violate the library-level-only rule, provided the implementation of controlled types does not rely on it. --Ted Baker **************************************************************** !section 3.9.1(03) !subject Controlled types in language-defined generic packages !reference RM95-3.9.1(3) !reference RM95-7.6 !reference RM95-A.8.1 !reference RM95-A.8.4 !reference RM95-A.10.1 !reference AARM95-A.5.2(46.a) !reference 95-5386.a Keith Thompson 95-11-15 !from Robert I. Eachus 95-11-16 !reference 95-5388.a Robert I. Eachus 95-11-16>> !discussion I agree with most of what Keith says, but: > Note, however, that implementations are advised to implement > Ada.Numerics.Discrete_Random.Generator as a controlled type. is misleading. The RM says: "Any storage associated with an object of type Generator should be reclaimed on exit from the scope of the object." Since other requirements seem to make it necessary (if you stay within standard Ada) for objects of type Generator to be access values or contain access values, it is not the Generators, but the designated objects that need to be reclaimed. This can be done by garbage collection, for example. However, there is a neater implementation that can be used in GNAT. Put the state information in the Generator object, and go "outside the language" to write to the object. (I think this can be done portably in GNAT with 'Unchecked_Access.) This is probably the most sensible implementation if the size of the state object is small. The same technique can be used with File_Type, again if the size is reasonable. Now the question arises, what if someone chooses to declare a constant of type Generator? (Notice that this is not a problem with File_Type, since Create and Open take in out parameters.) Currently, it seems that this should not affect the operation of Discrete_Random and therefore must be supported. No problem, as long as there is no requirement that the be preelaboratable. I think it is clear that implementations are allowed to make generators non-preelaboratable. Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is... **************************************************************** !section 3.9.1(03) !subject Controlled types in language-defined generic packages !reference RM95-3.9.1(3) !reference RM95-7.6 !reference RM95-A.8.1 !reference RM95-A.8.4 !reference RM95-A.10.1 !reference AARM95-A.5.2(46.a) !reference 95-5386.a Keith Thompson 95-11-15 !from Tucker Taft 95-11-16 !reference 95-5389.a Tucker Taft 95-11-16>> !discussion > It's tempting to implement the type File_Type in the various I/O packages > as a controlled type, with a Finalize routine that closes the file. > Unfortunately, such an implementation would mean that Ada.Sequential_IO > and Ada.Direct_IO can only be instantiated at the library level, a serious > (and undocumented) incompatibility with Ada 83. I can't find any wording > in the RM that forbids such an implementation. I don't believe we have to include such wording. Anything not disallowed by the RM is allowed. Hence, there is no permission to define Ada.Sequential_IO in a way that precludes it being instantiated in nested contexts. In any case, you can use controlled types without running into this problem. The solution is to declare a controlled type in a non-generic package, and then have make a component of File_Type be of that controlled type. > To avoid incompatibilities with Ada 83, it would actually be necessary to > forbid any language-defined generic package (or at least any of the ones > that exist in Ada 83) to contain the declaration of a record extension, > either in its specification or in its body. Any such declaration would > restrict the places at which such a package can be instantiated. Again, I don't believe we need such wording explicitly. Of course, a "NOTE" wouldn't hurt ;-). > ... > If restrictions are imposed on declaring controlled types (or, more > generally, record extensions) in language-defined generic packages, > it actually shouldn't be too much of a burden on implementers. > For example, the type Ada.Sequential_IO.File_Type, or even > Ada.Numerics.Discrete_Random.Generator, could be declared as a > record containing a component of a controlled type declared in an > implementation-defined library package. Right. We might want to add a NOTE to this effect as well. -Tuck **************************************************************** !section 3.9.1(03) !subject Controlled types in language-defined generic packages !reference RM95-3.9.1(3) !reference RM95-7.6 !reference RM95-A.8.1 !reference RM95-A.8.4 !reference RM95-A.10.1 !reference AARM95-A.5.2(46.a) !reference 95-5386.a Keith Thompson 95-11-15 !reference 95-5387.a Ted Baker 95-11-16 !reference 95-5388.a Robert I. Eachus 95-11-16 !reference RM95-3.9.1(4) !from Keith Thompson 95-11-17 !reference 95-5390.a Keith Thompson 95-11-17>> !discussion I wrote: > To avoid incompatibilities with Ada 83, it would actually be necessary to > forbid any language-defined generic package (or at least any of the ones > that exist in Ada 83) to contain the declaration of a record extension, > either in its specification or in its body. Actually, bodies are not a problem. RM95-3.9.1(4) forbids the declaration of a type extension in a generic body if the parent type is declared outside that body. Robert Eachus wrote: > I agree with most of what Keith says, but: > > > Note, however, that implementations are advised to implement > > Ada.Numerics.Discrete_Random.Generator as a controlled type. > > is misleading. The RM says: > > "Any storage associated with an object of type Generator should be > reclaimed on exit from the scope of the object." But the following paragraph in the AARM, A.5.2(46.a), says: 46.a Ramification: A level of indirection is implicit in the semantics of the operations, given that they all take parameters of mode in. This implies that the full type of Generator probably should be a controlled type, with appropriate finalization to reclaim any heap-allocated storage. Tucker Taft wrote: > I don't believe we have to include such wording. Anything not disallowed > by the RM is allowed. Hence, there is no permission to define > Ada.Sequential_IO in a way that precludes it being instantiated > in nested contexts. On the other hand, the wording about Ada.Numerics.Discrete_Random seems to establish the precedent that an implementation *may* preclude instantiations in nested contexts, particularly for generic packages that don't raise Ada 83 compatibility issues. I agree that it should be possible to instantiate any language-defined generic package in a nested context, but I'm not convinced this requirement can be inferred from the RM, particularly given paragraph 46.a, quoted above. (Avoiding the declaration of type extensions in generics is probably a good style guide for user code.) **************************************************************** !section 3.9.1(03) !subject Controlled types in language-defined generic packages !reference RM95-3.9.1(3) !reference RM95-7.6 !reference RM95-A.8.1 !reference RM95-A.8.4 !reference RM95-A.10.1 !reference AARM95-A.5.2(46.a) !reference 95-5386.a Keith Thompson 95-11-15 !reference 95-5388.a Robert I. Eachus 95-11-16 !from Bob Duff !reference 95-5396.a Robert A Duff 95-11-26>> !discussion > I agree with most of what Keith says, but: Well, I think Tucker correctly answered Keith's comment, but: > However, there is a neater implementation that can be used in GNAT. > Put the state information in the Generator object, and go "outside the > language" to write to the object. (I think this can be done portably > in GNAT with 'Unchecked_Access.) This is probably the most sensible > implementation if the size of the state object is small. The same > technique can be used with File_Type, again if the size is reasonable. 'Unchecked_Access won't quite work, since the parameter is of mode 'in', so you can't construct an access-to-variable value pointing to it. GNAT could use 'Unchecked_Access followed by an unchecked conversion. Or, the GNAT implementation-defined attribute 'Unrestricted_Access could be used. Both of those require pass-by-reference, so the full type would have to be a limited record. Alternatively, Tucker's suggestion -- putting the controlled type in a package with-ed by the generic -- works, and seems more elegant, though probably less efficient. > Now the question arises, what if someone chooses to declare a > constant of type Generator? ... Generator is a limited type, so you can't declare a constant object. You could have a constant view, such as an 'in' parameter, but we already know the 'in' parameter is some sort of reference to a *variable*, and the variable can of course be modified. - Bob **************************************************************** !section 3.9.1(03) !subject Controlled types in language-defined generic packages !reference RM95-3.9.1(3) !reference RM95-7.6 !reference RM95-A.8.1 !reference RM95-A.8.4 !reference RM95-A.10.1 !reference AARM95-A.5.2(46.a) !reference 95-5386.a Keith Thompson 95-11-15 !reference 95-5388.a Robert I. Eachus 95-11-16 !reference 95-5396.a Bob Duff 95-11-27 !reference 95-5397.a Robert I. Eachus 95-11-27>> !discussion (Basically, just agreeing...) Bob Duff said: > 'Unchecked_Access won't quite work, since the parameter is of mode 'in', > so you can't construct an access-to-variable value pointing to it. > GNAT could use 'Unchecked_Access followed by an unchecked conversion. That's what I had in mind, convert an access to constant to an access to variable. > Or, the GNAT implementation-defined attribute 'Unrestricted_Access > could be used. Both of those require pass-by-reference, so the full > type would have to be a limited record. Yep. > Generator is a limited type, so you can't declare a constant object. The case I was worried about is a "bastard" child package of Float_Random or Discrete_Random. I concluded that the auther gets either what they expect, or what they deserve. ;-) Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is... ****************************************************************