Constant declaration in Ada
Being new to Ada, I'm exploring its syntax and rules and I would like to draw attention on the code given next. Here I'm trying to set a variable Actual_Stiffness to hold a constant value. Its value is given by the product:
Actual_Stiffness := Stiffness_Ratio * Stiffness_Total
wh开发者_Python百科ere Stiffness_Total has been defined to be a constant Long_Float in the specification file Material_Data.ads and Stiffness_Total has a value already set in the ads file.
WITH Ada.Text_IO;
WITH Ada.Long_Float_Text_IO;
WITH Material_Data;
USE Material_Data;
PROCEDURE sample IS
Stiffness_Ratio : Long_Float;
Actual_Stiffness : CONSTANT Long_Float := Stiffness_Ratio * Stiffness_Total;
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;
--Ada.Long_Float_Text_IO.Put(Item => Actual_Stiffness);
--Ada.Text_IO.New_Line;
--Ada.Long_Float_Text_IO.Put(Item => Stiffness_Total);
END sample;
On compiling I get the warning message
warning: "Stiffness_Ratio" may be referenced before it has a value
and on running the program, Actual_Stiffness doesn't get the right value. I could defined Actual_Stiffness to be just a Long_Float (without adding CONSTANT) and then get its value from the product Actual_Stiffness := Stiffness_Ratio * Stiffness_Total after BEGIN in my program when Stiffness_Ratio would have already gotten a value. This would be the right thing to do.
My question is:
I have defined Stiffness_Total as a constant Long_Float with a prescribed value. How to define Actual_Stiffness to be constant also (as it won't be changing in the program) while keeping the ability for a user to interactively being able to enter a Stiffness_Ratio at the terminal? Is that even possible to do?
Thanks a lot..
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;
精彩评论