Sorry if it’s a really basic question. Im looking for a way to get the sum of entire array in compilation time to avoid Ravenscar profile “No_Implicit_Heap_Allocation” restriction
the “problematicVariable” raises a “No_Implicit_Heap_Allocation_Error”.
the “NoproblemVariable” is working… but need a lot of mechanical work…specially becouse the type MyLargeEnumerationtype could grow until thousands of elements…
¿Any ideas for a solution that will not need to write every element of the enumeration in the sum?
Here is the code:
pragma Profile (Ravenscar);
package Constants is
type MyLargeEnumerationtype is ( e1, e2, e3);
type MyBoringTableType is array (MyLargeEnumerationtype) of Natural;
M : constant MyBoringTableType :=
( e1 => 5,
e2 => 8,
e3 => 11);
Sum_Of_Boring_Table : constant Natural :=
(M (e1) + M(e2) + M(e3));
function FunctionSum return Natural;
end Constants;
package body Constants is
function FunctionSum return Natural is
Sum : Natural := 0;
begin
for I in M'Range loop
Sum := Sum + M(I);
end loop;
return Sum;
end FunctionSum;
end Constants;
pragma Profile (Ravenscar);
with constants; use constants;
package test is
type KnowedSizetype is array ( 1 .. Sum_OF_Boring_Table) of Natural;
type notknowedSizeType is array ( 1 .. functionsum) of Natural;
NoproblemVariable : KnowedSizetype;
ProblematicVariable : notknowedSizeType;
end test;
Ok, first off could you edit your post to delimit/enclose the code with three backticks? (`) This will activate the code-formatter on the forum.
Second, have you tried to make a separate package for the type-definitions in a pure package? This will help in that pure packages are forbidden to have state. Then, for the package Constants, making it pure (or preelaborate).
The “reduction expression” is a natural way to sum all of the elements of an array. See Ada RM 4.5.10. Given an array A, you can write A'Reduce("+", 0) and immediately get the result of combining all of the components of A using the “+” operator, with the result initialized to zero before beginning the summation.
Just as a side note, I copy/pasted your code into an online Ada compiler, changed the illegal characters (it probably didn’t support wide_wide text) and it compiled without any errors. No mention of heap allocation. Can you clarify what line is giving you the heap allocation error?
hello, thank you for the formatting tip.
I’ve tried to use your workaround:
package types is
pragma pure (types);
type MyLargeEnumerationtype is ( e1, e2, e3);
type MyBoringTableType is array (MyLargeEnumerationtype) of Natural;
end types;
and for Constants:
with types; use types;
package Constants is
pragma Preelaborate;
M : constant MyBoringTableType :=
( e1 => 5,
e2 => 8,
e3 => 11);
Sum_Of_Boring_Table : constant Natural :=
(M (e1) + M(e2) + M(e3));
I finally get error “non-static constant in preelaborated unit” pointing to the line:
(M (e1) + M(e2) + M(e3));
Thank you very much for your advice.
I needed to recompile using -gnat2022 flag
I’ve use this:
function F_Sum return Natural is (M'Reduce("+",0));
It’s working making the sum of all elements, It’s much more elegant and compact than using a body and everything get defined in the specification… but unfortunately it still triggering the Implicit Heap Allocation restriction.
but unfortunately it still triggering the Implicit Heap Allocation restriction.
That seems weird, since there is nothing that requires any allocation of a large temporary in M'Reduce(...). I could believe that some other part of your code requires heap allocation, but not this use of the Reduce attribute.
It seems that the allocation error is raised in any variable which dimension depends of a function call , or M’Reduce… etc …
examples:
total : constant Natural := M(e1) + M(e2) + M(e3); --and here I need to manually add another thousands elements with the real size that M array could be..
a : array ( 1 .. F_Sum) of integer; -- raises an error
b : array ( 1 .. M'Reduce("+"),0) of Integer; -- raises an error
c : array ( 1 .. total) of Integer; -- It's ok
```
(Q: Is there a secondary stack during elaboration?)
I tried this (GCC 14.1.0):
1. pragma Profile (Ravenscar);
2. pragma Ada_2022;
3. package Issue_105 is
4. type Table is array (Natural range <>) of Integer;
5. Values : constant Table := [1, 2, 3];
6. Another_Table : Table (1 .. Values'Reduce ("+", 0));
|
>>> error: violation of restriction "No_Implicit_Heap_Allocations"
>>> error: from profile "Ravenscar" at line 1
7. end Issue_105;
7 lines: 2 errors
Looking at the expanded code (with -gnatG) I can’t see any reason for claiming heap allocation. There is elaboration code, unsurprisingly, a very plain loop.
I suppose it is possible that the heap is used rather than the secondary stack for library-level objects whose size is not known at compile-time. I’ll let someone more familiar with the GNAT run-time model to answer that, and your other question!
Thinking about it some more, you can see that it’s one thing to declare a definite object at compile time and assign a value during elaboration, but quite another if the object is indefinite. So using heap allocation (which is what the code does if you remove the Ravenscar requirement) is the Right Thing. We shouldn’t (I wouldn’t) expect the compiler to cater for what’s probably an unusual use case for this feature, where the requred size could in an ideal world be calculated beforehand.