Constant declaration in Ada

Since the 'Stiffness_Ratio' is not determined until run-time, the compiler cannot calculate the value of 'Actual_Stiffness' at compile time as you have asked it to. You will have to make 'Actual_Stiffness' into a non-constant variable and initialize it with the computation after 'Stiffness_Ratio' has a value. (You may even be able to keep it as a CONSTANT within the function as long as the stiffness ratio has a value at the time the actual stiffness is computed.)

This is standard in most programming languages.

So, to answer your question:

  • No, you cannot define Actual_Stiffness as a constant as desired.

  • A moderately close approximation is that you determine the Stiffness_Ratio value outside this procedure, and pass that value into the procedure as a parameter. But then the Actual_Stiffness is only constant for the duration of the procedure, not for all time.

On the other hand, this is likely to be more useful; someone can run the program with multiple values of the stiffness ratio at different times, thus doing many simulations in a single run.


In Ada, it is perfectly possible and reasonable to declare variables in the middle of your function. Just like in all other programming languages (at least Java, C, C++, C#, python) you can make a scope explicitly anywhere:

declare
   A : My_Type := Val;
begin
   Use(A);
end;

which means your constant can be declared after receiving the runtime value:

WITH Ada.Text_IO;
WITH Ada.Long_Float_Text_IO;
WITH Material_Data;
USE Material_Data;

PROCEDURE sample IS

   Stiffness_Ratio  : Long_Float;

BEGIN -- main program
   Ada.Text_IO.Put("Enter stiffness ratio: ");
   Ada.Long_Float_Text_IO.Get(Item => Stiffness_Ratio);
   Ada.Long_Float_Text_IO.Put(Item => Stiffness_Ratio);

   --Ada.Text_IO.New_Line;
   declare
      Actual_Stiffness : CONSTANT Long_Float :=  Stiffness_Ratio * Stiffness_Total;
   begin
      Ada.Long_Float_Text_IO.Put(Item => Actual_Stiffness);
   end;
   --Ada.Text_IO.New_Line;
   --Ada.Long_Float_Text_IO.Put(Item => Stiffness_Total);
END sample;

For instance, consider the following non-recursive implementation of Euclid's Greatest Common Divisor algorithm:

   function GCD(X,Y : Integer) return Integer is
   begin
      declare
         X : Integer := GCD.X;
         Y : Integer := GCD.Y;
      begin
         while Y /= 0 loop
            declare
               temp : Integer := X;
            begin
               X := Y;
               Y := temp mod Y;
            end;
         end loop;
         return X;
      end;
   end GCD;

Inside GCD, the parameters X and Y are always constant, because they are declared as in. This is to avoid confusion; if we allowed assigning to the variable, the programmer might think that he was causing a side-effect, as would be the case if the parameter were marked out.

Programming in Ada 2012 by John Barnes recommends in this case to declare a variable with a different name in the scope of the function itself. On page 194, section 11.2:

   function Sum(List: Cell_Ptr) return Integer is
      Local: Cell_Ptr := List;
      (...)

Which leaves the programmer able to refer to List, the constant and unchanged initial value. In the case of the GCD program given above, referring to that value in the body of the loop would lead to incorrect behaviour.

Hiding X and Y by adding an inner scope with variables of the same name means that we would need to explicitly include the scope of the variable to make that mistake. Try changing X := Y to X := GCD.Y in the loop body, and observe that GCD(91,21) now returns 21 rather than 7.

Finally, note that the inner scope can be given a name by prepending a label:

   Inner:
   declare
      X : Integer := 0;
   begin
      Use(Inner.X); -- explicitly the X in that scope
   end Inner;