Version 1.1 of acs/ac-00081.txt

Unformatted version of acs/ac-00081.txt version 1.1
Other versions for file acs/ac-00081.txt

!standard 3.08(12)          03-09-17 AC95-00081/01
!class amendment 03-09-17
!status received no action 03-09-17
!status received 03-09-13
!subject Components of an array type
!summary
!appendix

!topic Proposal for a "(null array)" aggregate
!reference RM95-4.3.3(2)
!from Niklas Holsti 03-09-26
!keywords null arrays, array aggregates, private types
!discussion

Summary

   The expression '(null array)' should be allowed as an array aggregate
   and understood to mean an array of the type and dimensions expected
   in the context, with null index ranges.

Existing similar constructs

   1. '(null record)' for record aggregates with no components.
   2. The expression "" for null strings.

Expected impact on compilers

   Mainly syntactic sugar. Possibly a new place where overloading
   resolution is needed, but then the existing array-aggregate
   notations can also include overloaded parts and need resolution.

Motivation

   Currently, a null array aggregate must be written with an explicit
   specification of the null index range and the value of the
   non-existent array component. For example, given

      type Vector_Type is array (Positive range <>) of Float;

   a null Vector_Type aggregate can be written as

      (1 .. 0 => 0.0)

   The drawbacks of this are:

   a) The index range is usually irrelevant, but must be given.
   b) The component value is certainly irrelevant, but must be given.

   Point (b) is particularly troublesome when the component type is a
   private type or a private formal generic parameter. Examples follow.

Example 1: An array with a private component type.

   Assume the following package declaration:

      package Secrets is
         type Secret is private;
         type Secret_List is array (Positive range <>) of Secret;
         procedure Publish (My_Secrets : in Secret_List);
      private
         ...
      end Secrets;

   A client of Secrets that wants to publish an empty list of secrets
   must currently declare a dummy variable with an apparently undefined
   initial value and probably irrelevant index bounds:

      Null_List : Secret_List (1 .. 0);
      ...
      Publish (My_Secrets => Null_List);

   The proposal would allow simply

      Publish (My_Secrets => (null array));

   which gets rid of the irrelevant index bounds 1 .. 0 and the
   apparent undefined value of the Null_List variable, and their
   potential to confuse the human reader and analysis tools.

   In the current standard, the provider of the private type may
   try to help its clients to create empty lists of secrets by
   defining a dummy constant secret value:

      package Secrets is
         ...
         No_Secret : constant Secret;
         ...
      private
         ...
      end Secrets

    Then, a client can publish an empty secrets list by

       Publish (My_Secrets => (1 .. 0 => No_Secret));

    However, in the private part of the Secrets package declaration
    there must be a definition of No_Secret, of the form

         No_Secret : constant Secret := <expression>;

    The <expression> is often an aggregate, and often this aggregate
    uses private types defined in other packages, forcing also these
    packages to provide dummy constants of these types, etc. The
    contagion spreads...

Example 2: Formal generic type parameter

   Assume the following declaration of a package that implements
   flexible but bounded one-dimensional arrays, generic in the index
   type, component type and a normal (fixed-length) array type:

      generic
         type Index is (<>);
         type Component is private;
         type Vector is array (Index range <>) of Component;
      package Bounded_Vectors is
         type Bounded_Vector (Max_Length : Natural) is private;
         ...
         function To_Vector (Item : Bounded_Vector) return Vector;
         -- Converts the bounded vector to an ordinary vector.
         ...
      end Bounded_Vectors;

   Depending on the services provided in the package, there may be
   several places in the package body where a null Vector is
   needed, but again a null array aggregate cannot be written
   because it needs to have a dummy Component value, which is not
   available. The body must resort to apparently undefined null
   Vector variables, as in Example 1.

   If a new formal parameter for a dummy Component is added to the
   generic formals, the instantiation must provide a concrete value.
   If the type is actually private even at the instantiation point,
   or contains private components, the contagion spreads as in
   Example 1.

Minor things

   The qualified form Some_Array_Type'(null array) should also be
   allowed.

   The issue of multi-dimensional arrays may need more thought.
   It seems more likely that the actual index ranges are significant
   for multi-dimensional null arrays than for single-dimensional
   null arrays; it may be significant to know which dimensions
   are null ranges. This can be expressed by the ordinary aggregate
   notation. The '(null array)' notation should be usable as a
   subaggregate, which allows the index range of the "top"
   dimensions to be specified. For example, a two-dimensional
   array aggregate with the first index range 3 .. 7 and the
   second index range null could be expressed as

      (3 .. 7 => (null array))

   The analogous aggregate with the first index range null and
   the second index range 3 .. 7 cannot be expressed with the
   '(null array)' form, but has to be written in the currently
   accepted form and must specify both index ranges and a dummy
   component value.

Potential problems

   1. Although the index range of a null array is usually irrelevant
      to the application program, clearly '(null array)' must have
      some First and Last attributes. What should they be? Can this
      be solved in the same way as for an array aggregate in
      positional notation?

   2. If the index type contains only a single value (for example,
      an enumeration with a single literal) it is not clear to me
      if null arrays can exist. Perhaps '(null array)' should be
      illegal or cause a bounded error in such cases.

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

From: Adam Beneschan
Sent: Friday, September 26, 2003  3:08 PM


> !topic Proposal for a "(null array)" aggregate
> !reference RM95-4.3.3(2)
> !from Niklas Holsti 03-09-26
> !keywords null arrays, array aggregates, private types
> !discussion
>
> Summary
>
>    The expression '(null array)' should be allowed as an array aggregate
>    and understood to mean an array of the type and dimensions expected
>    in the context, with null index ranges.

It seems to me that this proposal has come up before, possibly before
the Ada 95 standard was written, and was rejected.  Personally, I
think it's a good idea.  I do find myself writing things like (1 .. 0
=> blah-blah-blah) often, or defining a *variable* with a null range
(which I can't define as a constant, even though it is a constant),
and it seems silly.

> Potential problems
>
>    1. Although the index range of a null array is usually irrelevant
>       to the application program, clearly '(null array)' must have
>       some First and Last attributes. What should they be? Can this
>       be solved in the same way as for an array aggregate in
>       positional notation?

It probably can be solved in the same way as for the null string
literal.  For string literals, 4.2(10) says "The bounds of this array
value are determined according to the rules for positional_array_-
aggregates (see 4.3.3), except that for a null string literal, the
upper bound is the predecessor of the lower bound.  4.3.3(26) says
that in such a case, the lower bound is "that of the corresponding
index range in the applicable index constraint, if defined, or that of
the corresponding index subtype, if not".  The index range of a null
array could be determined in the same way.  (If (null array) is
allowed to refer to an entire multi-dimensional array, this would
apply to each index range.)

The fly in the ointment here is that it doesn't handle cases in which
the lower bound of the index subtype has no predecessor.  In fact,
this is already the case with string literals:

    procedure Test89 is

        type Str is array (Integer range <>) of Character;

        procedure Proc (S : Str) is
        begin
            ...
        end Proc;

    begin
        Proc ("");
    end Test89;

This program is illegal, because for the array represented by the null
string literal, the language rules say the lower bound is
Integer'First and the upper bound is the predecessor of the lower
bound, which does not exist.  (See also AI95-138.)  This feature is
unlikely to cause a problem for string literals, since the predefined
String type has an index range of Positive.  However, it would cause
serious problems for a (null array) type, since it would be much more
common to use this for an array whose index subtype is Integer (or
some other integer type) or an enumeration type.

If (null array) is added to the language, I'd propose modifying
4.3.3(26) so that if there is no applicable index constraint, the
lower bound is that of the corresponding index subtype, except that in
the case of a null array aggregate or null string literal, if the
lower bound of the corresponding index subtype has no predecessor,
then the lower bound of the aggregate is the *successor* of the lower
bound of the corresponding index subtype.  If, in this case, the lower
bound has no successor, Constraint_Error would be raised, as specified
in 3.5(22).  (We could make 4.9(34) apply too, but we'd have to
modify the rest of 4.9 to indicate when (null array) would be
considered a "static expression".)  This would take care of the next
issue:

>    2. If the index type contains only a single value (for example,
>       an enumeration with a single literal) it is not clear to me
>       if null arrays can exist. Perhaps '(null array)' should be
>       illegal or cause a bounded error in such cases.

More likely, "should be illegal or cause Constraint_Error to be
raised".

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

From: Randy Brukardt
Sent: Monday, September 29, 2003  7:55 PM

AI-287 gives us <> to mean the default value of a component. So
    (1..0 => <>)
is a null array. It's a minor pain to look up the index subtype (but I usually
just use 1..0 and see if the compiler chokes), but it's not that big of a deal.

The alternative is writing a number of pages of RM rules to make these useful
(and then having people confused by the rules, whatever they are). Hard to say
if it is worth it.

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

From: Tucker Taft
Sent: Monday, September 29, 2003  8:16 PM

Good point.  That seems to answer the need for a null array
adequately.  Interestingly, "(null record)" can presumably
be represented with "(others => <>)" obviating the need
for the special "(null record)" syntax as well.

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

Questions? Ask the ACAA Technical Agent