!standard 13.13.2 (31) 01-02-13 AI95-00260/00 !standard 13.13.2 (34) !class amendment 01-02-13 !status received 01-02-13 !priority Low !difficulty Medium !subject How to replace S'Class'Input with custom versions !summary !problem S'Class'Output writes the tag of an item with String'Output. This routine cannot be replaced, so it is not possible to write the tag in an arbitrary user-defined format (to match an external standard, for example). A more general problem is that the dispatching accomplished by S'Class'Input cannot be duplicated in normal user code. (If it could, that mechanism could be used to eliminate the problem above by overridding the appropriate operations). !proposal (* Ideas needed *) !discussion A significant annoyance. !example !ACATS test !appendix From: Pascal Obry Sent: Wednesday, January 31, 2001 3:00 PM Hello, I have a comment/question about an Ada feature. The current implementation for S'Class'Output seems to be not flexible enough for some job. Let's look at the definition for 'Class'Ouput: << 29. S'Class'Output S'Class'Output denotes a procedure with the following specification: 30. procedure S'Class'Output( Stream : access Ada.Streams.Root_Stream_Type'Class; Item : in T'Class) 31. First writes the external tag of Item to Stream (by calling String'Output(Tags.External_Tag(Item'Tag) - *Note 3.9::.) and then dispatches to the subprogram denoted by the Output attribute of the specific type identified by the tag. >> The problem here is the way the tag is written using String'Output. My goal was to write (on disk using streams) objects in XML. But this is not possible because the tag is written with the string's bounds (String'Output) ! So there is some binary data dumped into the XML file !!! Of course it is possible to write the tag myself, but then it will be just impossible to read back the object from the disk... To summarize: It is possible to stream an object to disk only in binary format. It would be nice to be able to control the way the tag is written. I don't have a proposal for this right now... I have talked about this issue with my ACT support and we came to the conclusion that it is just impossible to do what I wanted! Please let me know if this is clear enough or if you need some more info. **************************************************************** From: Tucker Taft Sent: Wednesday, January 31, 2001 5:40 PM It is definitely frustrating that the dispatching performed by S'Class'Input cannot be duplicated by "normal" user code. Essentially one wants to be able to dispatch using an (internal) tag rather than an object. Alternatively, one wants to be able to construct an object with default initialization given a tag. Some kind of "magic" generic might be defined to provide this capability, or something similar. This definitely will require some head-scratching. **************************************************************** From: Pascal Obry Sent: Saturday, March 17, 2001 2:57 PM Hello, Please have a look at this first proposal. I have tried to write something but this is the very first time I do something like that. I'm not sure the wording is correct, not talking about my english :) Can you told me if this all this makes sense to you or if it is just not the right way to approach the problem. I have tried to follow current AI structure. << !summary The stream input/output attributes are not flexible enough. The problem is for the tag handling of tagged object. With the current implementation it is not possible for example to redefine the 'Read and 'Write to have the object streamed as an XML object. We propose a solution to solve this problem. !problem The problem is for the tag handling of tagged object. With the current implementation it is not possible for example to redefine the 'Read and 'Write to have the object streamed as an XML object. Indeed the tag is defined as a string. It is possible to change the tag string value by using Ada.Tags facilities. But the tag will always be a string : an unbounded object. Each time the tagged object will be streamed the tag string value will be written preceded by the string bound which are binary data. There is no way to avoid these binary data to be sent. In other word, there is no way to stream an object with a plain text representation. !proposal Have the possibility to set the way the 'Class'Output and 'Class'Input handle the tag with the new attribute 'Tag_Format. Values for this attributes is of type Ada.Tags.Tag_Output: type Tag_Ouput is (Constrained, Unconstrained); 'Tag_Format is set to Unconstrained by default. This is the current behavior. In this mode 'Class'Output will call String'Output on the tag string to output the tag. And 'Class'Input will call String'Input to read the tag. So with Unconstrained the tag's bounds are used. If it is set to Constrained then the tag will be written using String'Write (and read using String'Read). In this case the tag's bounds are not used. The definition for S'Class'Input and S'Class'Output must be changed accordingly. !discussion We could find some other ways to implement this feature. This is certainly the lightest one as it requires only one new attributes on tagged record. Another solution would have been to define two new attributes 'Read_Tag and 'Write_Tag for reading and writing a tag value. These attributes would have the current default and could have been overridden by users. It would have been possible to solve the problem described here with this mechanism. Something like: procedure Write_Tag (S : access Streams.Root_Stream_Type'Class; O : Object); for Object'Write_Tag use Write_Tag; procedure Read_Tag (S : access Streams.Root_Stream_Type'Class; O : Object); for Object'Read_Tag use Read_Tag; !example Here is an example that show the problem. Let's say that we want to stream an object with an XML encoding: with Ada.Streams; package Class is use Ada; type Object is tagged record V : Integer := 2; end record; procedure Write (S : access Streams.Root_Stream_Type'Class; O : Object); for Object'Write use Write; for Object'External_Tag use ""; end Class; package body Class is procedure Write (S : access Streams.Root_Stream_Type'Class; O : Object) is begin String'Write (S, ""); String'Write (S, Integer'Image (O.V)); String'Write (S, ""); String'Write (S, ""); end Write; end Class; with Ada.Text_IO.Text_Streams; with Class; procedure Main is use Ada; O : Class.Object; begin Class.Object'Class'Output (Text_IO.Text_Streams.Stream (Text_IO.Current_Output), O); end Main; This program output will be something like: ^A^@^@^@^H^@^@^@ 2 The 8 first characters are binary representation for the tag bound. This is no way to bypass that, so there is no way to stream an object with an XML representation. Using the new 'Tag_Format attributes it is possible to control the tag output. By changing the Class spec to read: with Ada.Streams; package Class is use Ada; type Object is tagged record V : Integer := 2; end record; procedure Write (S : access Streams.Root_Stream_Type'Class; O : Object); for Object'Write use Write; for Object'External_Tag use ""; for Object'Tag_Format use Constrained; end Class; We now have the following output: 2 >> I hope to hear from you soon, Pascal. **************************************************************** From: Pascal Obry Sent: Sunday, March 18, 2001 3:19 PM Please ignore my proposal as it is not working for reading the Tag. When reading an object (by calling 'Class'Input) the Tag is not known so the string bounds are needed ! I'll try to find something else... **************************************************************** From: Randy Brukardt Sent: Monday, March 19, 2001 5:20 PM Too bad. We have an (empty) AI on this subject just waiting for a proposal. (It seems like a problem worth solving.) Tucker pointed out that the problem of being unable to handle the tag is really one of being unable to write a new implementation of T'Class'Input, and *that* is caused by not having a way to dispatch based on a (internal) tag value (or, equivalently, being able to create a default-initialized object from a tag value). We can write code to read the tag however you need, you can look up the tag with Internal_Tag, but you can't write the needed dispatching and/or object creation. Tuck's musings suggested that perhaps a "magic" generic with this capability would be the way to go. Perhaps you can find a solution and make a proposal based on that idea?? **************************************************************** From: Pascal Obry Sent: Wednesday, April 04, 2001 11:30 AM Hello, Here is a proposal for an Ada stream extenssion, the goal is to provide more control on the Tag for streamed object. << !summary The stream input/output attributes are not flexible enough. The problem is for the tag handling of tagged object. With the current implementation it is not possible for example to redefine the 'Read and 'Write to have the object streamed as an XML object. We propose a solution to solve this problem. !problem The problem is for the tag handling of tagged object. With the current implementation it is not possible for example to redefine the 'Read and 'Write attribute to have the object streamed as an XML object. Indeed the tag is defined as a string. It is possible to change the tag string value by using Ada.Tags facilities. But the tag will always be a string : an unbounded object. Each time the tagged object will be streamed the tag string value will be written preceded by the string bounds which are binary data. There is no way to avoid these binary data to be sent. In other word, there is no way to stream an object with a plain text representation. !proposal Have the possibility to set the way the 'Class'Output and 'Class'Input handle the tag with the new attributes. Two new attributes form are proposed: S'External_Tag'Read This attribute can be used to set the right function to use for reading the tag on a stream. This function will be called by S'Class'Input instead of the default one. The function prototype must be: function Read (S : access Streams.Root_Stream_Type'Class) return Ada.Tags.Tag; S'External_Tag'Write This attribute can be used to set the right function to use for writing the tag on a stream. This function will be called by S'Class'Output instead of the default one. The procedure prototype must be: procedure Write (S : access Streams.Root_Stream_Type'Class; Tag : Ada.Tags.Tag); The definition for S'Class'Input and S'Class'Output must be changed accordingly. !discussion This proposal does not really introduce new attributes. The S'External_Tag attribute can be composed with 'Read and 'Write. This change is upward compatible as it does not change the semantic for streamed object when it is not used. !example Here is an example that show the problem. Let's say that we want to stream an object with an XML encoding: with Ada.Streams; package Class is use Ada; type Object is tagged record V : Integer := 2; end record; procedure Write (S : access Streams.Root_Stream_Type'Class; O : Object); for Object'Write use Write; for Object'External_Tag use ""; end Class; package body Class is procedure Write (S : access Streams.Root_Stream_Type'Class; O : Object) is begin String'Write (S, ""); String'Write (S, Integer'Image (O.V)); String'Write (S, ""); String'Write (S, ""); end Write; end Class; with Ada.Text_IO.Text_Streams; with Class; procedure Main is use Ada; O : Class.Object; begin Class.Object'Class'Output (Text_IO.Text_Streams.Stream (Text_IO.Current_Output), O); end Main; This program output will be something like: ^A^@^@^@^H^@^@^@ 2 The 8 first characters are binary representation for the tag bound. This is no way to bypass that, so there is no way to stream an object with an XML representation. Using the new 'External_Tag'Read and 'External_Tag'Write attributes it is possible to control the tag input/output. By changing the Class spec to read: with Ada.Streams; package Class is use Ada; type Object is tagged record V : Integer := 2; end record; for Object'External_Tag use "object"; procedure Write (S : access Streams.Root_Stream_Type'Class; O : Object); for Object'Write use Write; procedure Write (S : access Streams.Root_Stream_Type'Class; Tag : Ada.Tags.Tag); -- Implementation not shown. This function: -- 1) output character '<' -- 2) output Ada.Tags.External_Tag (Tag) -- 3) output character '>' for Object'External_Tag'Write use Write; function Read (S : access Streams.Root_Stream_Type'Class) return Ada.Tags.Tag; -- Implementation not shown. This function: -- 1) read first character, raise Ada.Tags.Tag_Error if it is not '<' -- 2) read the tag (let's call it Tag_String) -- 3) check for end of tag which is '>' (raise Ada.Tags.Tag_Error if no -- such character on the stream) -- 4) return Ada.Tags.Internal_Tag (Tag_String) for Object'External_Tag'Read use Read; end Class; We now have the following output: 2 >> Let me know what you think about this proposal ? Do you need something else ? ****************************************************************