!standard 11.4.1(02) 05-11-22 AI95-00438/02 !standard 11.4.1(06) !standard 11.4.1(16) !class binding interpretation 05-10-21 !status Amendment 200Y 05-10-21 !status ARG Approved 8-0-3 05-11-19 !status work item 05-10-21 !status received 05-10-17 !priority Medium !difficulty Easy !subject Stream attribute availability for limited language-defined types !summary The language-defined limited type Ada.Exceptions.Exception_Occurrence has available stream attributes. !question Per AI-195, a stream attribute of a limited type is available at a place only if it was defined by an attribute definition clause that is visible at the place. The visible part of the declaration of Ada.Exceptions as specified by 11.4.1(2)..11.4.1(7) does not contain the declaration of suitable subprograms nor the appropriate attribute_definition_clause. Only the private part is left unspecified. The language of 11.4.1(16) sets forth requirements for the implementation of these attributes, but they do not appear to be available. Should they be available? (Yes.) !recommendation (See summary.) !wording [Note: This wording assumes AI-441 is approved.] Add the following to the end of the visible part Ada.Exceptions: procedure Read_Exception_Occurrence (Stream : not null access Ada.Streams.Root_Stream_Type'Class; Item : out Exception_Occurrence); procedure Write_Exception_Occurrence (Stream : not null access Ada.Streams.Root_Stream_Type'Class; Item : in Exception_Occurrence); for Exception_Occurrence'Read use Read_Exception_Occurrence; for Exception_Occurrence'Write use Write_Exception_Occurrence; Add "with Ada.Streams;" to the start of this package. Replace 11.4.1(16) by (moving this to Static Semantics): Write_Exception_Occurrence writes a representation of an exception occurrence to a stream; Read_Exception_Occurrence reconstructs an exception occurrence from a stream (including one written in a different partition). !discussion 11.4.1(16) discusses the implementation of these attributes, so there is a clear intent that they actually can be called. We checked all of the language-defined limited types to see if they should support streaming: Directory_Entry_Type (A.16): no, what would it mean? Exception_Occurrence (11.4.1): yes, should stream. File_Type (A.8, others): no, surely you don't want to stream the contents. Generator (A.5.2): this could be streamed, but the package provides type State as a nonlimited version of a Generator, so there isn't much need. Group_Budget (D.14.2): no, probably a runtime object anyway. Limited_Controlled (7.6): no, does not need to stream. Root_Stream_Type (13.13.1): no. streaming a stream? Hopefully not. Search_Type (A.16): no, a temporary thing anyway. Suspension_Object (D.10): no, again, a runtime object. Timer (D.14.1): no, again, a runtime object. Timing_Event (D.15): no, again, a runtime object. Limited_Controlled might need some explanation. While the package Ada.Finalization is a remote types package, only types that have available attributes need to be streamed. This allows users to create remote types derived from Limited_Controlled without Limited_Controlled itself being externally streamable. That's important, because making Limited_Controlled externally streamable would be a huge incompatibility: any type derived from it that has "really limited" components (such as a task or protected component) would need to have stream attributes defined. For Exception_Occurrence, we've declared procedures and the stream attributes explicitly in the visible part. We considered three options for handling this: (1) A textual rule saying that the attributes are available. That would require some form of compiler magic to avoid name pollution (this could not be expressed in pure Ada). (2) Declaring the subprograms and attribute specifications at the end of the package. The subprograms in this case would be primitive and thus would be inherited on derivation. That could cause various side-effects. In addition, there is a use clause incompatibility, in that the new names might conflict with existing user names. (3) Declaring the subprograms in a nested package, followed by the attribute specifications at the end of the package. We still have the use clause incompatibility, but it is less likely because there is only one name made visible. We chose the second option, as it isn't as gimmicky as (3), and doesn't require compiler magic like (1). We prefer to avoid magic as Ada users often use these package specifications as examples of how to write Ada packages, and it is preferable that they can actually write similar packages themselves. The incompatibilities of (2) are not considered to be a major issue. The names of the procedures are specific enough that they're unlikely to occur in user code. We could have eliminated the incompatibility completely by giving the routines names that included some non-Latin-1 characters, but that is even more gimmicky that (3), so it was also rejected. !corrigendum 11.4.1(02) @drepl @xcode<@b Ada.Exceptions @b @b Exception_Id @b; Null_Id : @b Exception_Id; @b Exception_Name(Id : Exception_Id) @b String;> @dby @xcode<@b Ada.Streams; @b Ada.Exceptions @b @b Exception_Id @b; Null_Id : @b Exception_Id; @b Exception_Name(Id : Exception_Id) @b String;> !corrigendum 11.4.1(06) @drepl @xcode< @b Save_Occurrence(Target : @b Exception_Occurrence; Source : @b Exception_Occurrence); @b Save_Occurrence(Source : Exception_Occurrence) @b Exception_Occurrence_Access; @b ... -- @i<@ft> @b Ada.Exceptions;> @dby @xcode< @b Save_Occurrence(Target : @b Exception_Occurrence; Source : @b Exception_Occurrence); @b Save_Occurrence(Source : Exception_Occurrence) @b Exception_Occurrence_Access;> @xcode< @b Read_Exception_Occurrence (Stream : @b Ada.Streams.Root_Stream_Type'Class; Item : @b Exception_Occurrence); @b Write_Exception_Occurrence (Stream : @b Ada.Streams.Root_Stream_Type'Class; Item : @b Exception_Occurrence);> @xcode< @b Exception_Occurrence'Read @b Read_Exception_Occurrence; @b Exception_Occurrence'Write @b Write_Exception_Occurrence;> @xcode<@b ... -- @i<@ft> @b Ada.Exceptions;> !corrigendum 11.4.1(16) @drepl @i<@s8> The implementation of the Write attribute (see 13.13.2) of Exception_Occurrence shall support writing a representation of an exception occurrence to a stream; the implementation of the Read attribute of Exception_Occurrence shall support reconstructing an exception occurrence from a stream (including one written in a different partition). @dby Write_Exception_Occurrence writes a representation of an exception occurrence to a stream; Read_Exception_Occurrence reconstructs an exception occurrence from a stream (including one written in a different partition). !ACATS test ACATS C-Tests should be constructed to check that Ada.Exceptions.Exception_Occurrence can be streamed. (Indeed, it would be useful to check most of the non-limited types as well.) !appendix From: Thomas Quinot Sent: Friday, April 22, 2005 4:05 AM Per AI-195, a stream attribute of a limited type is available at a place only if it was defined by an attribute definition clause that is visible at the place. We know of a number of cases where users assume that Exception_Occurrence'{Read,Write} are available for application code, and this seems to be a reasonable expectation because of the language of 11.4.1(16), which sets forth requirements for the implementation of these attributes. Unfortunately, the visible part of the declaration of Ada.Exceptions as specified by 11.4.1(2)..11.4.1(7) does not contain the declaration of suitable subprograms nor the appropriate attribute_definition_clause. Only the private part is left unspecified. This looks like a hole in the specification. **************************************************************** From: Pascal Leroy Sent: Friday, April 22, 2005 4:29 AM > Per AI-195, a stream attribute of a limited type is available > at a place only if it was defined by an attribute definition > clause that is visible at the place. > > We know of a number of cases where users assume that > Exception_Occurrence'{Read,Write} are available for > application code, and this seems to be a reasonable > expectation because of the language of 11.4.1(16), which sets > forth requirements for the implementation of these attributes. That's interesting. Note that AI 195 is not really the culprit, and that the bug has been there from day 1, since 13.13.2(36) says that a reference to Write or Read is illegal for a limited type. > Unfortunately, the visible part of the declaration of > Ada.Exceptions as specified by 11.4.1(2)..11.4.1(7) does not > contain the declaration of suitable subprograms nor the > appropriate attribute_definition_clause. Only the private > part is left unspecified. I agree that we want to show attribute_definition_clauses for Read and Write in the specification of Ada.Exceptions, and that maybe we want a comforting sentence saying that these attributes are available in the visible part. I don't think we want to pollute the specification with the "suitable subprograms", though. Implementers will have to do some magic there. **************************************************************** From: Bob Duff Sent: Friday, April 22, 2005 7:00 AM I agree, except: why require magic? Why not just declare these in the normal way (picking names that are unlikely to conflict with existing user-defined names)? **************************************************************** From: Thomas Quinot Sent: Friday, April 22, 2005 7:20 AM A drawback of such a non-magic solution is that it forces Ada.Exceptions to always depend upon Ada.Streams. **************************************************************** From: Tucker Taft Sent: Friday, April 22, 2005 9:28 AM We might want to put them in a subpackage, so they don't become primitive operations of the Exception_Occurrence type. E.g.: package Ada.Exceptions is ... type Exception_Occurrence is ... package Exception_Occurrence_Streams is procedure Read(... procedure Write(... end Exception_Occurrence_Streams; for Exception_Occurrence'Read use Exception_Occurrence_Streams.Read; ... end Ada.Exceptions; **************************************************************** From: Randy Brukardt Sent: Thursday, October 20, 2005 6:21 PM Pascal Leroy wrote replying to me: >> This [the e-mail listed above] seems like a candidate for AC-111 >> (corrections). But I don't know what the correction actually is. >> Tucker suggested >> a nested package: > >This is messy because RM95 and RM95+TC11 are very much unclear. Because >this type is limited, its stream attributes can only be used if they have >been specified, but the visible part of Ada.Exceptions doesn't show an >attribute definition clause, and the private part is >implementation-defined. The only hint we have is 11.4.1(16), but that's >not normative. So I'd say that strictly speaking streaming this type >ought to have been illegal in Ada 95 (I know that our customers do stream >exception occurrences, so obviously we are not abiding by the letter of >the Book). I agree. In any case, AI-195 is a BI, so it applies to RM95. And as a BI, it says that there was never any intent that you had to look in the private part. >I have a serious concern here, because this problem can possibly exist for >each and every predefined limited type in the language. Maybe some >implementation has defined Ada.Numerics.Float_Random.Generator'Write in >the private part of Ada.Numerics.Float_Random, and suddenly the >availability rules are going to break customer code. Nasty. Tough. Looking into the private part is always bad taste, if not wrong. >If we want to solve this problem, we should do it globally rather than >focus on Ada.Exceptions. Now you're treading on very thin ice. For Ada.Exceptions, there is clear evidence that the designers wanted it to be streamable (in the form of 11.4.1(16)). No such evidence exists for any other type (well, other than the ARG attaching "Remote_Types" to Ada.Finalization, which is an after-the-fact judgment. Note that the pragma is illegal on Ada.Finalization, given the rules in E.2.2 - that seems in bad taste to me). > Here are the predefined limited types that I > found (I am not entirely sure that I didn't miss some), with an indication > of my feeling as to whether or not they need to stream. >- Directory_Entry_Type: no, what would it mean? >- Exception_Occurrence: should stream. >- File_Type: no, surely you don't want to stream the contents. >- Generator: a pure value, should stream. >- Group_Budget: no, probably a runtime object anyway. >- Limited_Controlled: part of a remote types package, better stream. >- Root_Stream_Type: streaming a stream? Hopefully not. >- Search_Type: no, a temporary thing anyway. >- Suspension_Object: no, again, a runtime object. >- Timer: no, ditto. >- Timing_Event: no, ditto. >At any rate, I certainly don't want to pollute existing predefined >packages with nested packages and other junk, so I think we should just >say something like: > >"The attributes Read, Write, Input and Output for T are available at the >end of the visible part of P." And now you've fallen through the ice. >and let the implementers figure out how to do this using some form or >magic. (The only magic is to create stream subprograms that don't pollute >the namespace; it's always OK to add a with Ada.Streams if you need one >because it has no visible effect; note in particular that Ada.Streams is >pure so there are no nasty categorization effects.) But that magic is incredibly disruptive. It affects *everything*, and it has absolutely no user benefit. Now, if the only magic was a pragma (this might give you a case of deja-vu): pragma Streaming_Available (Generator); I'd put up with it. But the default attributes for Generator are not going to work in any implementation, as Generator has to either be Rosen-trick type, or a limited controlled type with heap pointer. So you definitely do need first-class subprograms to do the trick. Pragmatically, both Ada.Finalization.Controlled and Ada.Exceptions are completely magic in our compiler anyway. So the effort is the same no matter what the rules are, because the symboltable is created by hand with a bunch of aggregates that have the right effect. So I wouldn't object too strongly to magic in those cases (although I would expect other implementers to do so). But I *would* object very strongly to requiring magic for Ada.Numerics.Float_Random, etc. Especially as this would be the *only* use of such magic; you're talking a weeks work for a feature which is never going to be used. Most likely, implementers would totally ignore the requirement, which is hardly of any benefit to users. Honestly, I see no problem with making the routines explicit. Their profiles are unlikely to conflict with anything in user code, and the names can make that even more unlikely too (I'd suggest Stream_Read and Stream_Write or something like that -- "Read" and "Write" are too likely to conflict). As procedures, there is no problem with inheritance (it will just work) - and that presumes someone is deriving from these types in the first place (only likely for Limited_Controlled). Yes, it will clutter the packages in question, but so what? So, either limit this to "magic" packages where there is clear requirements for streaming (Limited_Controlled and Exceptions), or forget the magic. (And "magic" means that the spec of Ada.Finalization is technically illegal for pragma Remote_Types. I think we ought to provide better examples than that to users; people do use the predefined stuff as examples of Ada style.) Note that both Bob and Tuck were against magic in the original exchange. Only you seemed in favor of it, so I think you might be on an island there. Probably we need to ask the ARG to know for sure. **************************************************************** From: Pascal Leroy Sent: Friday, October 21, 2005 3:46 AM > Tough. Looking into the private part is always bad taste, if > not wrong. I couldn't agree more. > >If we want to solve this problem, we should do it globally > rather than > >focus on Ada.Exceptions. > > Now you're treading on very thin ice. I treading on perfectly firm ground when I say that we should at least take a look at end and every predefined limited type and make a decision as to whether or not it should stream. If we don't make Limited_Controlled streamable, we have plenty of egg on our face. > >At any rate, I certainly don't want to pollute existing predefined > >packages with nested packages and other junk, so I think we > should just > >say something like: > > > >"The attributes Read, Write, Input and Output for T are available at > >the end of the visible part of P." > > But that magic is incredibly disruptive. It affects > *everything*, and it has absolutely no user benefit. For a library-based compiler, it doesn't seem that hard to me: just implement a switch that says to the lexer "please allow consecutive underscores" and write your source as follows: procedure Stream__Read ... -- Note the two underscores. for T'Read use Stream__Read... Compile this source with the switch, and ship the resulting library to your customers: it won't create name clashes, and I am ready to bet that all the rest of you compiler will happily deal with the name Stream__Read. For a source-based compiler where you keep recompiling the same source over and over, this is not so simple. But anyway, implementation arguments are not exactly relevant here. > Now, if the only magic was a pragma (this might give you a > case of deja-vu): > > pragma Streaming_Available (Generator); > > I'd put up with it. But the default attributes for Generator > are not going to work in any implementation, as Generator has > to either be Rosen-trick type, or a limited controlled type > with heap pointer. In our implementation Generator is a simple array wrapped in a limited record. The limitedness ensures that it is passed by reference, and then it is updated using 'Address. Not sure if there are implementations that actually use the Rosen trick: that would seem likely to confuse optimizers if you ask me. As for a controlled implementation, that is certainly an option, but it would be awfully expensive. > Pragmatically, both Ada.Finalization.Controlled and > Ada.Exceptions are completely magic in our compiler anyway. They are not particularly magic for us, but then we have a trick to create identifiers with * in them, and that would take care of the name space pollution. > Honestly, I see no problem with making the routines explicit. > Their profiles are unlikely to conflict with anything in user > code, and the names can make that even more unlikely too (I'd > suggest Stream_Read and Stream_Write or something like that > -- "Read" and "Write" are too likely to conflict). As > procedures, there is no problem with inheritance (it will > just work) - and that presumes someone is deriving from these > types in the first place (only likely for Limited_Controlled). In my view, inheritance *is* a problem. If any (limited) controlled type gets a Stream_Read, there is the potential bug that someone will call it, or that it will have unpleasant interferences with overriding_indicators, etc. So if you don't want magic, I definitely want a nested package. The downside of having a name that could conflict with use clauses is nothing compared with the nuisance of inheriting these procedures. So in that case I would go for: package Stream_Attributes is procedure Read ...; procedure Write ...; end Stream_Attributes; for T'Read use Stream_Attributes'Read; for T'Write use Stream_Attributes'Write; This should go at the very end of the visible part. > Note that both Bob and Tuck were against magic in the > original exchange. Only you seemed in favor of it, so I think > you might be on an island there. Probably we need to ask the > ARG to know for sure. You're right, I am isolated, so I suggest adding the nested packages. If you wish to ask the ARG, feel free to do so. **************************************************************** From: Randy Brukardt Sent: Friday, October 21, 2005 9:13 PM I was writing up the AI for this when I was struck by a problem. Inheritance *is* a problem, regardless of how we write, because "availability" is inherited for tagged types. There's no problem for Exceptions.Exception_Occurrence or Float_Random.Generator (they're not tagged). But for Limited_Controlled, this means that *every* descendant has available stream attributes. And having available stream attributes means that they *must* be defined if in fact any of the components do not have available stream attributes. That's of course necessary so that calling Limited_Controlled'Class'Read will work. But that's a horrible incompatibility: every limited type derived from Limited_Controlled (and I'm sure there is a lot of them in existing code) would need stream attributes if the extension components contained anything "really limited". Whether or not the program ever does any streaming. (While it would be good for programmers to use streaming more, being forced to do it is not likely to win any friends...) This leaves us with some very bad choices, since Remote_Types means that Limited_Controlled must be "externally streamable". (1) Give up on OOP for streaming of limited types. (After everything we've done to make limited and nonlimited equivalent, this would be horrible. Plus the loss to OOP.) (2) Give up on Ada.Finalization being a remote types package. (3) Magic. Define Limited_Controlled to be externally streamable, but *not* have available attributes. (That is, no attributes would be defined in the spec, thus they are not available.) A remote type derived from it would have to define attributes to make them available. Limited_Controlled itself couldn't be streamed directly, but the DS annex could (they're empty types, so its not an issue.) (4) Magic 2. Leave things as they are. Add an AARM note that Limited_Controlled is not externally streamable, so transporting it won't work - but doing so is useless anyway, so no one will care. But it can be used as the basis for types that are remote types. DS implementations would have to do *something* if it is encountered, but we don't care what. (5) ??? Any ideas? **************************************************************** From: Tucker Taft Sent: Friday, October 21, 2005 9:13 PM Limited_Controlled is limited. Why would I expect to be able to stream it? I must have missed something here, since it seems clear to me that we never expected language-defined limited types to be streamable (with the one "exception" of Exception_Occurrence, of course ;-). Ahhh! I see the problem. Our requirement on Remote_Types that all visible types support external streaming should have said that all visible types *with any available stream attributes* shall support external streaming. The same should go for Pure packages. ****************************************************************