411 REFERENCE · Wikibooks
Ada Programming/Control
Reference material by Wikibooks contributors. This retains its source identity and is not 411 news reporting.
__TOC__
Conditionals
Conditional clauses are blocks of code that will only execute if a particular expression (the condition) is true.
if-else
The if-else statement is the simplest of the conditional statements. They are also called branches, as when the program arrives at an if statement during its execution, control will "branch" off into one of two or more "directions". An if-else statement is generally in the following form:
if condition then
statement;
else
other statement;
end if;
If the original condition is met, then all the code within the first statement is executed. The optional else section specifies an alternative statement that will be executed if the condition is false. Exact syntax will vary between programming languages, but the majority of programming languages (especially procedural and structured languages) will have some form of if-else conditional statement built-in. The if-else statement can usually be extended to the following form:
if condition then
statement;
elsif condition then
other statement;
elsif condition then
other statement;
...
else
another statement;
end if;
Only one statement in the entire block will be executed. This statement will be the first one with a condition which evaluates to be true. The concept of an if-else-if structure is easier to understand with the aid of an example:
with Ada Text_IO;
use Ada Text_IO;
...
type Degrees is new Float range -273.15 .. Float'Last;
...
Temperature : Degrees;
...
if Temperature >= 40.0 then
Put_Line ("Wow!");
Put_Line ("It's extremely hot");
elsif Temperature >= 30.0 then
Put_Line ("It's hot");
elsif Temperature >= 20.0 then
Put_Line ("It's warm");
elsif Temperature >= 10.0 then
Put_Line ("It's cool");
elsif Temperature >= 0.0 then
Put_Line ("It's cold");
else
Put_Line ("It's freezing");
end if;
In Ada, conditional statements with more than one conditional do not use short-circuit evaluation by default. In order to mimic C/C++'s short-circuit evaluation, use and then or or else between the conditions.
case X is
when 1 =>
execute the following if X is 1:
Walk_The_Dog;
when 5 =>
execute the following if X is 5:
Launch_Nuke;
when 8 | 10 =>
execute the following if X is 8 or 10:
Sell_All_Stock;
when others =>
execute the following if X is none of the above cases:
Self_Destruct;
end case;
The subtype of X must be a discrete type, i.e. an enumeration, or signed or unsigned integer type.
In Ada, one advantage of the case statement is that the compiler will check the coverage of the choices, that is, all the values of the subtype of variable X must be present or a default branch when others must specify what to do in the remaining cases.
For procedures:
return;
For functions:
return Value;
goto
Goto transfers control to the statement after the label.
goto Label;
Dont_Do_Something;
<<Label>>
...
The goto statement is not allowed to transfer control in the following conditions:
outside a body;
between alternatives of a case statement, if statement, or select statement;
between different exception handlers; or from an exception handler of a handled_sequence_of_statements back to its sequence_of_statements.
Is goto evil?
Since Professor Dikstra wrote his article Go To Statement Considered Harmful, goto is considered bad practice in structured programming languages, and, in fact, many programming style guides forbid the use of the goto statement. But it is often overlooked that any return which is not the last statement inside a procedure or function is also an unconditional statement — a goto in disguise. There is an important difference though: a return is a forward only use of goto. Exceptions are also a type of goto statement; and note that they need not specify where they are going to.
Therefore, if you have functions and procedures with more than one return statement you are breaking the structure of the program similarly to a use of goto. In practice, nearly every programmer is familiar with a 'return' statement and its associated behavior; thus, when it comes down to readability the following two samples are almost the same:
procedure Use_Return is
begin
Do_Something;
if Test then
return;
end if;
Do_Something_Else;
return;
end Use_Return;
procedure Use_Goto is
begin
Do_Something;
if Test then
goto Exit_Use_Goto;
end if;
Do_Something_Else;
<<Exit_Use_Goto>>
return;
end Use_Goto;
Also, note that the goto statement in Ada is considered safer than in other languages, since it doesn't allow you to transfer control in certain conditions where the control structure is susceptible to be broken.
Because the use of a goto requires the declaration of a label, it can be considered as readable as the use of return. So if readability is a concern instead of a strict programming rule such as "don't use goto", then it is possible to consider the use of goto than multiple return statements. Although, it is best to use the structured approach whenever possible, where neither goto nor multiple returns are needed, for instance:
procedure Use_If is
begin
Do_Something;
if not Test then
Do_Something_Else;
end if;
return;
end Use_If;
Endless_Loop :
loop
Do_Something;
end loop Endless_Loop;
The loop name (in this case, "Endless_Loop") is an optional feature of Ada. Naming loops is nice for readability but not strictly needed. Loop names are
useful though if the program should jump out of an inner loop, see below.
While_Loop :
while X <= 5 loop
X := Calculate_Something;
end loop While_Loop;
Until_Loop :
loop
X := Calculate_Something;
exit Until_Loop when X > 5;
end loop Until_Loop;
Exit_Loop :
loop
X := Calculate_Something;
exit Exit_Loop when X > 5;
Do_Something (X);
end loop Exit_Loop;
In Ada the exit condition can be combined with any other loop statement as well. You can also have more than one exit statement. You can also exit a named outer loop if you have several loops inside each other.
For_Loop :
for I in Integer range 1 .. 10 loop
Do_Something (I)
end loop For_Loop;
You don't have to declare both subtype and range as seen in the example. If you leave out the subtype then the compiler will determine it by context; if you leave out the range then the loop will iterate over every value of the subtype given.
As always with Ada: when "determine by context" gives two or more possible options then an error will be displayed and then you have to name the type to be used. Ada will only do "guess-works" when it is safe to do so.
The loop counter I is a constant implicitly declared and ceases to exist after the body of the loop.
Array_Loop :
for I in X'Range loop
X (I) := Get_Next_Element;
end loop Array_Loop;
With X being an array. Note: This syntax is mostly used on arrays — hence the name — but will also work with other types when a full iteration is needed.
Working example
The following example shows how to iterate over every element of an integer type.
range_1.adb
with Ada Text_IO;
procedure Range_1 is
type Range_Type is range -5 .. 10;
package T_IO renames Ada Text_IO;
package I_IO is new Ada Text_IO Integer_IO (Range_Type);
begin
for A in Range_Type loop
I_IO.Put (Item => A,
Width => 3,
Base => 10);
if A < Range_Type'Last then
T_IO.Put (",");
else
T_IO.New_Line;
end if;
end loop;
end Range_1;
See also
Wikibook
Ada Programming
Ada Reference Manual
5 3 If Statements
5 4 Case Statements
5 5 Loop Statements
5 6 Block Statements
5 7 Exit Statements
5 8 Goto Statements
6 5 Return Statements
Control
es:Programación en Ada/Sentencias y estructuras de control