Version 1.3 of ais/ai-00087.txt

Unformatted version of ais/ai-00087.txt version 1.3
Other versions for file ais/ai-00087.txt

!standard A.10.3 (00)          00-01-25 AI95-00087/04
!class confirmation 95-09-29
!status Response 2000 00-01-25
!status WG9 approved 96-12-07
!status ARG approved 12-0-0 96-10-07
!status ARG approved 7-0-2 96-06-17
!status work item 95-09-29
!status received 95-09-29
!priority Low
!difficulty Easy
!qualifier Error
!subject Saving and restoring Current_Output
!summary
Current_Output and Set_Output can be used to save and restore Text_IO's current output file, using an object of type File_Access.
!question
It's clear from the example in section A.4.3 of the Rationale that one should be able to use the subprograms Current_Output and Set_Output to save and restore Text_IO's current output file, using an object of type File_Access. However, given what I believe to be a typical implementation of Text_IO, this won't work.
Assume that Text_IO declares a hidden aliased object of type File_Type, called, say, Current_Output_Object. (How the type File_Type is declared is irrelevant here; it may be a pointer, a descriptor record, a descriptor number, or whatever, as long as the view from the body of Text_IO is not limited.) The bodies of the Current_Output and Set_Output functions can then simply be:
procedure Set_Output (File : in File_Type) is begin Current_Output_Object := File; end Set_Output;
function Current_Output return File_Type is begin return Current_Output_Object; end Current_Output;
function Current_Output return File_Access is begin return Current_Output_Object'access; end Current_Output;
Recall that the example in Rationale-A.4.3 looks like this:
procedure P(...) is New_File : File_Type; Old_File_Ref : constant File_Access := Current_Output; begin Open(New_File, ...); Set_Output(New_File); -- use the new file Set_Output(Old_File_Ref.all); Close(New_File); end P;
If we are using the Text_IO implementation above, Old_File_Ref will be initialized to point to Current_Output_Object, the first call to Set_Output will change the value of Current_Output_Object, the second call to Set_Output will have no effect, and the Close will close a file that's still being used as the current output file. Thus any operations on Current_Output after the call to P will be erroneous by RM95-A.10.3(23).
Is the suggested implementation of Text_IO legal? If so, the example in the Rationale is non-portable. If not, how can the prohibition be inferred from the RM?
!response
The suggested implementation is wrong.
A.7(2) states, "In the remainder of this section, the term file is always used to refer to a file object...." A.10(5) states, "At the beginning of program execution the default input and output files are the so-called standard input file and standard output file." By A.7(2), this can be paraphrased as follows: "At the beginning of program execution the default input and output file objects are the so-called standard input file object and standard output file object." That is, the terms "default input file object" and "default output file object" are not names of distinct file objects, but of a ROLE played by a file object. That is, the only way that a single file object can be both the standard input file and the default input file is if the default input file is not a file object distinct from all other file objects. (The role played by the file objects currently acting as the default objects is described by A.10(4): "If no file is specified, a default input file or a default output file is used." This is the closest the RM comes to defining what a default file is, and the terms should probably have been italicized.)
!ACATS test
ACATS test CXAA016 tests that Current_Output and Set_Output can be used to save and restore Current_Output (although it does not try writing to Current_Output afterwards).
!appendix

!section RM-A.10.3(00)
!subject Saving and restoring Current_Output
!reference RM95-A.10.3
!reference Rationale-A.4.3
!from Keith Thompson 95-08-29
!reference as: 95-5263.a Keith Thompson 95-8-29>>
!discussion

It's clear from the example in section A.4.3 of the Rationale that one
should be able to use the subprograms Current_Output and Set_Output
to save and restore Text_IO's current output file, using an object
of type File_Access.  However, given what I believe to be a typical
implementation of Text_IO, this won't work.

Assume that Text_IO declares a hidden aliased object of type File_Type,
called, say, Current_Output_Object.  (How the type File_Type is declared
is irrelevant here; it may be a pointer, a descriptor record, a descriptor
number, or whatever, as long as the view from the body of Text_IO is
not limited.)  The bodies of the Current_Output and Set_Output functions
can then simply be:

   procedure Set_Output (File : in File_Type) is
   begin
      Current_Output_Object := File;
   end Set_Output;

   function Current_Output return File_Type is
   begin
      return Current_Output_Object;
   end Current_Output;

   function Current_Output return File_Access is
   begin
      return Current_Output_Object'Access;
   end Current_Output;

Recall that the example in Rationale-A.4.3 looks like this:

   procedure P(...) is
      New_File     : File_Type;
      Old_File_Ref : constant File_Access := Current_Output;
   begin
      Open(New_File, ...);
      Set_Output(New_File);
      -- use the new file
      Set_Output(Old_File_Ref.all);
      Close(New_File);
   end P;

With the Text_IO implementation above, Old_File_Ref will be initialized
to point to Current_Output_Object, the first call to Set_Output will
change the value of Current_Output_Object, the second call to Set_Output
will have no effect, and the Close will close a file that's still being
used as the current output file.  Thus any operations on Current_Output
after the call to P will be erroneous by RM95-A.10.3(23).

Is the suggested implementation of Text_IO legal?  If so, the example
in the Rationale is non-portable.  If not, how can the prohibition be
inferred from the RM?

****************************************************************

!section RM-A.10.3(00)
!subject Saving and restoring Current_Output
!reference RM95-A.10.3
!reference Rationale-A.4.3
!reference 95-5263.a Keith Thompson 95-8-29
!from Norman Cohen
!reference as: 95-5264.a Norman H. Cohen 95-8-30>>
!discussion

I presume that Keith is playing devil's advocate here, i.e., that he
realizes that the semantics presumed by the Rationale are the desirable
and intended interpretation, but that he can't see anything in the RM
that requires such an interpretation.

(In brief, the "desirable" interpretation is that the current default
files are not file objects in their own right, but indirect references to
File_Type objects currently acting in the role of default file, and the
File_Access versions of the Current_XXX functions return pointers to the
indirectly referenced file objects; the effect of Set_XXX is to change
the indirect reference to refer to a different File_Type object.  The
implementation Keith has shown has different semantics, in which the
current default file is a separate File_Type object, the File_Access
version of Current_XXX returns a pointer to that object, and the effect
of Set_XXX to change the contents of that object to a copy of the
contents of some other File_Type object.  The semantics of this
interpretation are even more pernicious than Keith indicated:  A.14(2)
states, "Operations on one text file object do not affect the column,
line, and page numbers of any other file object."  Thus the sequence

   Set_Col(F, 1);
   Set_Output (F);
   Set_Col (2);  -- Acts on the default output file

must leave Col(F) equal to 1 and Col(Current_Output) equal to 2 if the
File_Access version of Current_Output returns some value other than
F'Access.)

Below are some arguments that the RM prohibits the implementation Keith
has shown.  I think these arguments are sufficiently obscure that a
ramification AI would be in order.  Indeed, one can argue that the RM
wording is misleading, and that a binding interpretation is in order, to
change the description of Set_Input in A.10.3(3) from "Sets the current
default input file to File," to "Causes File to be used henceforth as
the default input file," and similarly for the default output file in
A.10.3(6).  (I've never understood what a "current error file" is, other
than the file currently designated to be the result of the Current_Error
function, so I'm not sure what to do with the description of Set_Error
in A.10.3(6).)

Exegesis:

A.7(2) states, "In the remainder of this section, the term @i{file} is
always used to refer to a file object...."  A.10(5) states, "At the
beginning of program execution the default input and output files are the
so-called standard input file and standard output file."  By A.7(2), this
can be paraphrased as follows:  "At the beginning of program execution
the default input and output file objects are the so-called standard
input file object and standard output file object."  That is, the terms
"default input file object" and "default output file object" are not
names of distinct file objects, but of a ROLE played by a file object.
That is, the only way that a single file object can be both the standard
input file and the default input file is if the default input file is not
a file object distinct from all other file objects.  (The role played by
the file objects currently acting as the default objects is described by
A.10(4):  "If no file is specified, a default input file or a default
output file is used."  This is the closest the RM comes to defining what
a default file is, and the terms should probably have been italicized.)

****************************************************************

Questions? Ask the ACAA Technical Agent