[comp.lang.ada] Default initialization and address clauses.

smithd@software.org (Doug Smith) (04/09/91)

-- According to the Ada LRM, 13.5.8, address clauses should not be used to achieve overlays
-- of objects or overlays of program units.  However, I have unwittingly used just that
-- approach to hide information, create freelists of allocated memory, etc.  So far the
-- compilers I have used behave as expected, with one inconsistency.

-- Should an object that has an address clause also have default initializations applied?
-- Explicit initializations are not a big problem (I can control that).  But several times
-- now, my concientious attempts at providing reasonable default initialization while
-- going to extremes to hide implementation details has created portability problems.

-- The DEC Ada compiler does the initialization.  The Verdix compiler (several versions
-- old now) does not.  My first thought was that the DEC Ada compiler was correct, but
-- I'm not so sure.  If this feature were not so convenient and powerful, who would care?
-- I invite your comments on which behavior you believe is appropriate.  Keep in mind that
-- this is a very simplified example of the technique.  (Unchecked_Conversion does not
-- work in other situations I have encountered!)


with Text_IO;
with System;

procedure Test is
begin

   Try_Access_Types:
   declare

      type Pointer is access Integer;

      Pointer_Value   : Pointer := new Integer;
      Pointer_Value_2 : Pointer;               -- Overlay !!!
      for Pointer_Value_2 use at Pointer_Value'Address;

   begin
      if Pointer_Value_2 = null then
         Text_IO.Put_Line ("Your compiler initializes pointer " &
                           "declarations even with representation clauses.");
      else
         Text_IO.Put_Line ("Your compiler fails to initialize pointer " &
                           "declarations with representation clauses.");
      end if;
   end Try_Access_Types;


   Try_Record_Types:
   declare

      type R is record
          I : Integer := 13;
      end record;

      R_Value       : R := R'( I => 17 );
      R_Value_2     : R;                 -- Overlay !!!
      for R_Value_2 use at R_Value'Address;

   begin
      if    R_Value_2.I = 13 then
         Text_IO.Put_Line ("Your compiler initializes record component " &
                           "declarations even with representation clauses.");
      elsif R_Value_2.I = 17 then
         Text_IO.Put_Line ("Your compiler fails to initialize record component " &
                           "declarations with representation clauses.");
      end if;
   end Try_Record_Types;

end;

sampson@cod.NOSC.MIL (Charles H. Sampson) (04/10/91)

     In article <1991Apr8.174020.8176@software.org> smithd@software.org (Doug
Smith) writes that he is violating the LRM, 13.5(8) by using address clauses
to overlay data.  He then questions some of the execution results he is get-
ting, particularly when it comes to initializing these data.  His question is:
Can these data be reliably initialized as part of their declaration, or should
they be initialized dynamically?  To illustrate the problem, he gives two sim-
ilar code fragments, of which the following is one.

>with Text_IO;
>with System;
>
>procedure Test is
>begin
>
>   Try_Access_Types:
>   declare
>
>      type Pointer is access Integer;
>
>      Pointer_Value   : Pointer := new Integer;
>      Pointer_Value_2 : Pointer;               -- Overlay !!!
>      for Pointer_Value_2 use at Pointer_Value'Address;
>
>   begin
>      if Pointer_Value_2 = null then
>         Text_IO.Put_Line ("Your compiler initializes pointer " &
>                           "declarations even with representation clauses.");
>      else
>         Text_IO.Put_Line ("Your compiler fails to initialize pointer " &
>                           "declarations with representation clauses.");
>      end if;
>   end Try_Access_Types;
>
>end;

His complaint is that this code executes differently on different compilers.

     The reason for the erratic behaviour is that the above code is erroneous,
as Smith has pointed out, and the effect of executing erroneous code is un-
predictable [LRM 1.6(7)].  Looking at the code, I would expect the generated
code to first initialize Pointer_value, then initialize Pointer_value_2,
overwriting Pointer_value's value with NULL, which is apparently what happens
in most cases.  However, wondrous things sometimes happen deep inside com-
pilers, and the LRM doesn't require compiler writers to spend time on making
sure that the obvious thing happens to erroneous programs.

     One possibility that comes to mind in this case is that some compilers
accumulate blocks of static initial values out of line, and initialization
begins by moving these blocks into position on the stack, followed by evalua-
ting any non-static initial values.  With this approach, Pointer_value_2's
NULL is static and it will be overwritten after Pointer_value's allocator
is evaluated.

                                Charlie