CVS difference for ais/ai-00260.txt

Differences between 1.3 and version 1.4
Log of other versions for file ais/ai-00260.txt

--- ais/ai-00260.txt	2001/05/11 03:46:21	1.3
+++ ais/ai-00260.txt	2001/06/03 04:21:30	1.4
@@ -1,6 +1,7 @@
-!standard 13.13.2  (31)                               01-02-13  AI95-00260/00
+!standard 13.13.2  (31)                               01-06-02  AI95-00260/01
 !standard 13.13.2  (34)
 !class amendment 01-02-13
+!status work item 01-06-02
 !status received 01-02-13
 !priority Low
 !difficulty Medium
@@ -8,29 +9,257 @@
 
 !summary
 
+Two new stream attributes are proposed for tagged types. These attributes
+can be used to redefine the stream format of tags.
+
 !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).
+Consider, for example, XML objects, which are a text formal. With the current
+language definition, it is not possible to redefine the 'Read and 'Write
+attribute to have the object streamed as an XML object. This is surprising,
+as external tags are defined as strings. It is possible to change the external
+tag string value by using Ada.Tags facilities. But the tag will always
+be streamed as an unbounded string object. This means that the tag string value
+will be written preceded by the string bounds -- which are binary data. There
+is no way to prevent this binary data from being be sent. In other words, there
+is no way to stream an object with a plain text representation.
 
 !proposal
+
+Two new operational attributes are defined for reading and writing tags.
+These attributes are used in S'Class'Input and S'Class'Output.
+
+For every specific tagged subtype S, the following attributes are defined.
+
+   S'Tag_Write
+
+        procedure S'Tag_Write (S : access Streams.Root_Stream_Type'Class;
+                               Tag : Ada.Tags.Tag);
+
+	S'Tag_Write writes the value of Tag to Stream.
+
+   S'Tag_Read
+
+        function S'Tag_Read (S : access Streams.Root_Stream_Type'Class)
+            return Ada.Tags.Tag;
+
+	S'Tag_Read reads a tag from Stream, and returns its value.
 
-(* Ideas needed *)
+The Tag_Write and Tag_Read attributes of the parent type are inherited when
+a type is derived. The default implementation of Tag_Write is to call
+String'Output(Stream, Tags.External_Tag(Item'Tag)), which is what Ada 95
+defines as the way of writing tags to a stream. Similarly, the default
+implementation of Tag_Read is to return the value of
+Tags.Internal_Tag(String'Input(Stream)).
 
+User-specifed Tag_Read and Tag_Write attributes may raise an exception if
+presented with a tag value not in S'Class.
+
+S'Class'Input and S'Class'Output use S'Tag_Read and S'Tag_Write, respectively,
+to read and write tag values. The default implementations of S'Tag_Read and
+S'Tag_Write insure that programs not redefining these attributes get unchanged
+behavior.
+
 !discussion
+
+These attributes can be set on any tagged type, not just the root of a class.
+This is important so that stream representation can be controlled for types
+whose root is not in the user's control: controlled types, for example.
+
+We have to limit the tag values that can be presented to user-specified
+Tag_Read and Tag_Write routines, as otherwise they would have to be able to
+handle any tag value which might exist in the program. Similarly, we also
+have to mention that the result of S'Class'Input is converted to S'Class, to
+handle the case where some tag not in S'Class is presented to S'Class'Input.
+The wording "returns that result" does not have this effect, as conversions
+are defined as part of the execution of a return_statement. (This is a minor
+hole in Ada 95, which gets more serious with user-defined tag reading).
+
+Note that RM 13.13.1(31) is missing a right parenthesis in the call to
+String'Output, and it is missing the Stream parameter. But this paragraph will
+be replaced anyway in this proposal.
+
+!wording:
+
+Add after 13.13.1(27):
+
+For every subtype S of a specific tagged type T, the following operational
+attributes are defined.
+
+   S'Tag_Write
 
-A significant annoyance.
+        procedure S'Tag_Write (S : access Streams.Root_Stream_Type'Class;
+                               Tag : Ada.Tags.Tag);
 
+	S'Tag_Write writes the value of Tag to Stream.
+
+   S'Tag_Read
+
+        function S'Tag_Read (S : access Streams.Root_Stream_Type'Class)
+            return Ada.Tags.Tag;
+
+	S'Tag_Read reads a tag from Stream, and returns its value.
+
+The Tag_Write and Tag_Read attributes of the parent type are inherited as
+specified in 13.1. The default implementation of Tag_Write is to call
+String'Output(Stream, Tags.External_Tag(Item'Tag)) -- see 3.9. The default
+implementation of Tag_Read is to return the value of
+Tags.Internal_Tag(String'Input(Stream)).
+
+User-specifed Tag_Read and Tag_Write attributes may raise an exception if
+presented with a tag value not in S'Class.
+
+Replace 13.13.1(31) by:
+
+First writes the external tag of Item to Stream (by calling
+S'Tag_Write(Stream, Item'Tag)) and then dispatches to the subprogram denoted
+by the Output attribute of the specific type identified by the tag.
+
+Replace 13.13.1(34) by:
+
+First reads the external tag from Stream and determines the corresponding
+internal tag (by calling S'Tag_Read(Stream)) and then dispatches to the
+subprogram denoted by the Input attribute of the specific type identified by
+the internal tag; converts that result to S'Class and returns it.
+
 !example
 
+Here is an example that illustrates the problem. Let's say that we want to
+stream an object with an XML encoding:
+
+with Ada.Streams;
+package Class is
+
+   type Object is tagged record
+      V : Integer := 2;
+   end record;
+
+   procedure Write (S : access Ada.Streams.Root_Stream_Type'Class;
+                    O : Object);
+   for Object'Write use Write;
+
+   for Object'External_Tag use "<object>";
+
+end Class;
+
+package body Class is
+
+   procedure Write (S : access Ada.Streams.Root_Stream_Type'Class;
+                    O : Object) is
+   begin
+      String'Write (S, "<v>");
+      String'Write (S, Integer'Image (O.V));
+      String'Write (S, "</v>");
+      String'Write (S, "</object>");
+   end Write;
+
+end Class;
+
+
+with Ada.Text_IO.Text_Streams;
+with Class;
+
+procedure Main is
+   O : Class.Object;
+begin
+   Class.Object'Class'Output
+     (Ada.Text_IO.Text_Streams.Stream (Ada.Text_IO.Current_Output), O);
+end Main;
+
+This program output will be something like:
+
+   ^A^@^@^@^H^@^@^@<object><v> 2</v></object>
+
+The first 8 bytes (characters) are the binary representation for the tag bound.
+In Ada 95, there is no way to prevent these bytes from being written, so
+there is no way to stream an object with an XML representation.
+
+Using the new 'Tag_Read and 'Tag_Write attributes it is
+possible to control the tag input/output. By changing the Class spec to read:
+
+with Ada.Streams, Ada.Tags;
+package Class is
+
+   type Object is tagged record
+      V : Integer := 2;
+   end record;
+
+   for Object'External_Tag use "object";
+
+   procedure Write (S : access Ada.Streams.Root_Stream_Type'Class;
+		    O : Object);
+   for Object'Write use Write;
+
+   procedure Write (S : access Ada.Streams.Root_Stream_Type'Class;
+                    Tag : Ada.Tags.Tag);
+     -- Write a tag of the form "<External_Tag>".
+   for Object'Tag_Write use Write;
+
+   function Read (S : access Ada.Streams.Root_Stream_Type'Class)
+     return Ada.Tags.Tag;
+     -- Read a tag of the form "<External_Tag>".
+   for Object'Tag_Read use Read;
+
+end Class;
+
+package body Class is
+
+   procedure Write (S : access Ada.Streams.Root_Stream_Type'Class;
+                    O : Object) is
+   begin
+      String'Write (S, "<v>");
+      String'Write (S, Integer'Image (O.V));
+      String'Write (S, "</v>");
+      String'Write (S, "</object>");
+   end Write;
+
+   procedure Write (S : access Ada.Streams.Root_Stream_Type'Class;
+                    Tag : Ada.Tags.Tag) is
+     -- Write a tag of the form "<External_Tag>".
+   begin
+      Character'Write (S, '<');
+      String'Write (S, Ada.Tags.External_Tag (Tag));
+      Character'Write (S, '>');
+   end Write;
+
+   function Read (S : access Ada.Streams.Root_Stream_Type'Class)
+     return Ada.Tags.Tag is
+     -- Read a tag of the form "<External_Tag>".
+     Input : String (1..20);
+     Input_Len : Natural := 0;
+   begin
+     Character'Read (S, Input(1));
+     if Input(1) /= '<' then
+        raise Ada.Tags.Tag_Error;
+     end if;
+     Input_Len := 0;
+     for I in Input'range loop
+        Input_Len := I;
+        Character'Read (S, Input(I));
+        exit when Input(I) = '>';
+     end loop;
+     if Input(Input_Len) /= '>' or else -- Never found closing character
+        Input_Len <= 1 then -- Empty tag
+        raise Ada.Tags.Tag_Error;
+     end if;
+     return Ada.Tags.Internal_Tag (Input(1..Input_Len));
+   end Read;
+
+end Class;
+
+We now have the following output:
+
+   <object><v> 2</v></object>
+
+which is what we need to write XML.
+
 !ACATS test
 
+A C-Test should be constructed to test this feature.
 
 !appendix
 

Questions? Ask the ACAA Technical Agent