[net.lang.ada] Array Aggregates Questions

Mendal@SU-SIERRA.ARPA (Geoff Mendal) (12/11/85)

Dear Ada fanatics,

We would like to know why it is the case that an array aggregate
that specifies named associations in addition to an "others"
association must be qualified in the following contexts:

  (1) a generic actual parameter
  (2) an expression that follows an assignment compound delimiter

This seems to us to be too restrictive and a search of the
current Ada literature does not provide an adequate justification
for this restriction:

  ARM 4.3(7..8), 4.3.2(4..7), 4.7
  Booch sec 11.2 pp.148-150
  Barnes sec 6.2 pp. 71-72

Consider the following Ada code:

  Aggregate_Examples:
  declare
    subtype Shorty is String (1 .. 5);
    S : Shorty;
  begin
    S := (others => 'A');                       -- #1 valid
    S := ('A', 'B', others => 'C');             -- #2 valid
    S := (1=>'A', 2=>'B', others=>'C');         -- #3 invalid
    S := Shorty'(1=>'A', 2=>'B', others=>'C');  -- #4 valid
  end Aggregate_Examples;

What is the rationale for #3 being invalid? Is it not
the case that a compiler could figure out the subtype of
the aggregate in #3, just as it is able to do for the
other three cases? Since it is generally agreed that use of named
notation is more readable, better Ada style, etc., what
is it about named notation (as used in #3 above) that forces
qualification to be specified in order to determine the subtype of
an array aggregate?

It seems to us that qualification of aggregates is a special-
case in Ada. For instance, consider overloading of enumeration
literals:

  Enumeration_Literals_Example:
  declare
    type Vowels is ('U', 'I', 'O', 'E', 'A');
  
    C : Character;
    V : Vowel;
  begin
    C := 'A';                                  -- valid
    V := 'E';                                  -- valid
    if 'A' < 'U' then ... end if;              -- invalid
    if Character'('A') < 'U' then ... end if;  -- valid
    if 'A' < Vowel'('U') then ... end if;      -- valid
  end Enumeration_Literals_Example;

Note that qualification is not required in all cases here.
Qualification is only required when the enumeration literal(s) 
appear in an ambiguous context. Why is this not the case for
qualification of array aggregates (and aggregates in general)?

BONUS QUESTION:

What will the following function return (and why)?

  function Heck_If_I_Know return Boolean is
    type Multi is array (1..3, 1..2) of Integer;
  begin
    return (1=>(1=>4), 2=>(2=>5)) in Multi;
  end Heck_If_I_Know;

[This runs without exception on the Rolm/DG and returns True]

Geoff & Doug
-------

goodenou@wanginst.UUCP (John Goodenough) (12/20/85)

In article <8512110559.AB01317@ucbvax.berkeley.edu> Mendal@SU-SIERRA.ARPA (Geoff Mendal) writes:

>We would like to know why it is the case that an array aggregate
>that specifies named associations in addition to an "others"
>association must be qualified in the following contexts:
>
>  (1) a generic actual parameter
>  (2) an expression that follows an assignment compound delimiter
>
>This seems to us to be too restrictive and a search of the
>current Ada literature does not provide an adequate justification
>for this restriction.

I've been waiting for someone else to respond to your query, but since there
seem to be no takers ...

Let me modify your examples slightly:

    Aggregate_Examples:
    declare
        subtype Shorty is String (3..5);
        S : String (1..6);
    begin
        S(3..5) := (others => 'a');                             -- #1 legal
        S(3..5) := ('a', 'b', others => 'c');                   -- #2 legal
        S(3..5) := (3 => 'a', 4 => 'b', others => 'c');         -- #3 illegal
        S(3..5) := Shorty'(3 => 'a', 4 => 'b', others => 'c');  -- #4 legal
    end Aggregate_Examples;

Suppose in place of #3 we had written:

        S(3..6) := (2 => 'b', 3 => 'c', 4 => 'd', 5 => 'e');    -- #5 legal

This is completely legal, and is semantically similar to assigning a slice,
e.g., S(2..5).  (Of course, after the assignment, S(3) equals 'b' even though
within the aggregate, component 3 had value 'c').  But suppose the aggregate
is written:

        S(3..6) := (2 => 'b', 3 => 'c', others => 'd');         -- #6

Which components of the slice are to receive value 'd'?  The answer depends on
what bounds we give the aggregate.  If we use the lower bound of the index
subtype, then the aggregate is equivalent to ('d', 'b', 'c', 'd').  If we
implicitly qualify the aggregate with the subtype of the lhs, then CONSTRAINT_
ERROR will be raised because 2 is not in the range 3..6.  As I recall, it was
the difficulty of deciding how to treat examples like #6 that led to the
decision to make examples #6 and #3 illegal.

Named notation with an OTHERS clause is allowed for a non-generic actual
parameter and a function result because no implicit subtype conversion is
performed in these contexts; if the bounds of the aggregate do not match the
bounds of the formal parameter or function return subtype, CONSTRAINT_ERROR
will be raised.  In these contexts there is no ambiguity in determining the
required lower bound for an aggregate with an OTHERS clause, so the notation
is allowed.

But now that we have more experience with the language and can see the utility
of allowing examples like #3 when implementing Pascal-like sets, it could be
argued that examples #3 and #6 should be legal, and #6 should raise
CONSTRAINT_ERROR.  If these examples were made legal, a new semantic rule
(loosely stated) might be: if an aggregate has an others clause, it is
implicitly qualified by a subtype having the applicable index constraint.

John B. Goodenough                           goodenou@wanginst        (CSNET)
Wang Institute of Graduate Studies           decvax!wanginst!goodenou (UUCP)
Tyng Road, Tyngsboro, MA 01879               Goodenough@ISI           (ARPA)
(At Wang Institute until 6/1/86)             617-649-9731

stt@ada-uts.UUCP (12/27/85)

Another way to say this is: when "sliding" is legal,
named-with-others is not (since the bounds are indeterminate).