edit: fixed a copy-paste mistake in code
Looking at ways for making loops that work on slices more concise, such as:
for I in Input'Range loop
A (Offset + I - 1) := Input (I) * 2;
end loop;
I arrived at the following formula:
A (Offset .. Offset + Input'Length - 1) := [for X of Input => X * 2];
I find the second form more to the point.
Ignoring efficiency differences (favouring loops), the primary practical difference is that the aggregate formula raises a Constraint_Error when the Input array is empty.
There is no point in describing the problem in words as there’s more to it, so I’ll just post the sample code and a link to Compiler Explorer.
I looked at the GCC Bug List and found one open issue that’s somewhat, if not entirely, related [1].
I’ll wait a while before reporting the bug in case someone comes and explains to me that this is expected behaviour.
Compiler Explorer, old
Compiler Explorer, modified line 55
Code
with Ada.Assertions;
procedure Example is
type Arr is array (Positive range <>) of Integer;
A : Arr := [1, 999 ,3,4,5,6,7,8,9];
Non_Empty : constant Arr (1 .. 1) := [1];
Empty : Arr (1 .. 0);
Pos : constant Positive := 2; -- arbitrary position for insertion
begin
-- Copying array elements into a slice of another array
-- using an aggregate with iterator.
-- OK: non-empty "input"
A (Pos .. Pos + Non_Empty'Length - 1) := [for X of Non_Empty => X * 2];
-- A (2 .. 2) := [1 * 2];
Ada.Assertions.Assert (A (2) = Non_Empty (1) * 2);
-- --------------------------------------------------------------------
-- BAD: empty input
begin
A (Pos .. Pos + Empty'Length - 1) := [for X of Empty => X * 2];
-- A (2 .. 1) := [aggregate iterating over an empty array]
Ada.Assertions.Assert (False, "unreachable section");
exception
when Constraint_Error => Null; -- expected
end;
-- --------------------------------------------------------------------
-- OK: empty input without iterator (although with spurious warning message?)
begin
A (Pos .. Pos + Empty'Length - 1) := [for I in Empty'Range => Empty (I) * 2];
end;
-- --------------------------------------------------------------------
-- OK: empty input through a temporary
declare
Maybe_Empty : constant Arr := [for X of Empty => X * 2];
begin
A (Pos .. Pos + Maybe_Empty'Length - 1) := Maybe_Empty;
-- A (2 .. 1) := []
end;
-- --------------------------------------------------------------------
-- OK: empty input with a loop equivalent
for I in Empty'Range loop
A (Pos + I - 1) := Empty (I) * 2;
end loop;
-- --------------------------------------------------------------------
end Example;