Operators, Expressions & Short-Circuit Forms

Use Ada's arithmetic, relational, logical, membership and concatenation operators, understand operator precedence, the short-circuit forms 'and then' / 'or else', membership tests with ranges and choice lists, and how operators apply to strings and Booleans.

Ada's operators look familiar, but a few design decisions make expressions safer and clearer: logical 'and'/'or' always evaluate both operands while 'and then'/'or else' short-circuit; membership tests ('in', 'not in') check ranges, subtypes and lists of alternatives directly; and mixing 'and' with 'or' without parentheses is a compile error, so you can never misread precedence. This lesson covers every operator category with real examples.

Arithmetic and Relational Operators

Arithmetic: + - * / for all numeric types, mod and rem for integers, ** for exponentiation (integer exponent), and abs. Unary minus and plus exist. Relational: = and /= (not equal is written /=, not !=), <, <=, >, >=. Relational operators are defined for all scalar types and also for one-dimensional arrays of discrete components (so strings compare lexicographically: "Ada" < "Adb"). Equality is predefined for most types, including records and arrays (component-wise).

Precedence from highest to lowest: ** abs not; then * / mod rem; then unary + -; then binary + - &; then relational = /= < <= > >= in not in; then logical and or xor and then or else. Ada deliberately makes some combinations illegal without parentheses: 'A and B or C' is rejected, as is 'A B C' and '-A 2' is parsed as -(A 2). When in doubt, add parentheses — Ada style encourages it.

• Not equal is /= ; power is ** ; remainder operators mod and rem. • Strings and other discrete arrays compare lexicographically. • = is predefined for records and arrays. • Mixing and/or without parentheses is illegal — ambiguity is impossible.

Logical Operators and Short-Circuit Forms

and, or, xor and not work on Booleans (and bitwise on modular types and Boolean arrays). Crucially, plain 'and' and 'or' may evaluate both operands in any order. When the right operand must only be evaluated if the left one allows it — checking a pointer is not null before dereferencing it, or a divisor is non-zero before dividing — use the short-circuit forms 'and then' and 'or else', which evaluate left to right and stop as soon as the result is known.

• and / or / xor / not — both operands evaluated. • and then / or else — left to right, short-circuit. • Use short-circuit forms to guard: Ptr /= null and then Ptr.Value > 0.

Membership Tests and Concatenation

'X in 1 .. 10' tests a range, 'X in Natural' tests whether X satisfies a subtype's constraint, and since Ada 2012 'X in 2 | 4 | 6' tests a list of alternatives (which may mix values and ranges: X in 1 | 5 .. 9 | 20). 'not in' negates. Membership tests replace long chains of comparisons and read like the specification. The & operator concatenates arrays — strings, characters and single elements — producing a new array.

• X in L .. H / X in Subtype / X in A | B | C .. D. • not in negates the test. • & concatenates strings, characters and array components.

Code Examples

Covers precedence, membership tests, short-circuit guarding against division by zero, string comparison and concatenation. The array constant uses the Ada 2022 square-bracket aggregate [10, 0, 5]; GNAT warns that the older (10, 0, 5) form is obsolescent. Output: A + B * 2 = 13 (A + B) * 2 = 20 A ** 2 = 49 abs (B - A) = 4 A in 1 .. 10 = TRUE A in 2 | 4 | 6 = FALSE B not in Natural = FALSE and then avoided dividing by zero "Ada" < "Adb" = TRUE Concatenation : Ada 2022 True xor True = FALSE

with Ada.Text_IO; use Ada.Text_IO;

procedure L10_Ops is
   A : constant Integer := 7;
   B : constant Integer := 3;
   Values : constant array (1 .. 3) of Integer := [10, 0, 5];
   Divisor : constant Integer := Values (2);    --  zero
   Word : constant String := "Ada";
begin
   Put_Line ("A + B * 2      =" & Integer'Image (A + B * 2));
   Put_Line ("(A + B) * 2    =" & Integer'Image ((A + B) * 2));
   Put_Line ("A ** 2         =" & Integer'Image (A ** 2));
   Put_Line ("abs (B - A)    =" & Integer'Image (abs (B - A)));
   Put_Line ("A in 1 .. 10   = " & Boolean'Image (A in 1 .. 10));
   Put_Line ("A in 2 | 4 | 6 = " & Boolean'Image (A in 2 | 4 | 6));
   Put_Line ("B not in Natural = " & Boolean'Image (B not in Natural));
   --  Short-circuit: the right operand is evaluated only when needed.
   if Divisor /= 0 and then A / Divisor > 1 then
      Put_Line ("never printed");
   else
      Put_Line ("and then avoided dividing by zero");
   end if;
   Put_Line ("""Ada"" < ""Adb"" = " & Boolean'Image (Word < "Adb"));
   Put_Line ("Concatenation  : " & Word & " " & "2022");
   Put_Line ("True xor True  = " & Boolean'Image (True xor True));
end L10_Ops;

Operator Precedence (high → low)

Lower rows bind more loosely; mixing different logical operators requires parentheses.

if Ptr /= null and Ptr.Count > 0 then if Ptr /= null and then Ptr.Count > 0 then

Plain 'and' may evaluate the dereference even when Ptr is null; 'and then' guarantees left-to-right short-circuit evaluation.

if A > 0 and B > 0 or C > 0 then if (A > 0 and B > 0) or C > 0 then

Ada rejects mixing 'and' and 'or' without parentheses to rule out precedence mistakes.

if X != 0 then if X /= 0 then Ada's inequality operator is /=.

Which expression evaluates B only if A is True? A. A and B B. A and then B C. A or B D. A xor B

B. A and then B — the short-circuit form.

How is 'not equal' written in Ada? A. != B. <> C. /= D. ~= Is 'if A and B or C then' legal Ada? A. Yes B. No — mixing and/or needs parentheses C. Only with -gnat2022 D. Only for Booleans

B. No — Ada requires parentheses to make the grouping explicit.

What does 'X in 1 | 5 .. 9' test? A. X equals 1 or 5 or 9 B. X is 1 or in the range 5 to 9 C. X is between 1 and 9 D. Syntax error

B. X is 1 or in the range 5 .. 9 — a membership test with a choice list.

Predict the output of the operator example.

Real output: A + B * 2 = 13 (A + B) * 2 = 20 A ** 2 = 49 abs (B - A) = 4 A in 1 .. 10 = TRUE A in 2 | 4 | 6 = FALSE B not in Natural = FALSE and then avoided dividing by zero "Ada" < "Adb" = TRUE Concatenation : Ada 2022 True xor True = FALSE

1  **   abs   not
2  *    /     mod   rem
3  +x   -x                    (unary)
4  +    -     &               (binary adding)
5  =  /=  <  <=  >  >=  in  not in
6  and  or  xor  and then  or else   (cannot be mixed without parentheses)
with Ada.Text_IO; use Ada.Text_IO;

procedure L10_Ops is
   A : constant Integer := 7;
   B : constant Integer := 3;
   Values : constant array (1 .. 3) of Integer := [10, 0, 5];
   Divisor : constant Integer := Values (2);    --  zero
   Word : constant String := "Ada";
begin
   Put_Line ("A + B * 2      =" & Integer'Image (A + B * 2));
   Put_Line ("(A + B) * 2    =" & Integer'Image ((A + B) * 2));
   Put_Line ("A ** 2         =" & Integer'Image (A ** 2));
   Put_Line ("abs (B - A)    =" & Integer'Image (abs (B - A)));
   Put_Line ("A in 1 .. 10   = " & Boolean'Image (A in 1 .. 10));
   Put_Line ("A in 2 | 4 | 6 = " & Boolean'Image (A in 2 | 4 | 6));
   Put_Line ("B not in Natural = " & Boolean'Image (B not in Natural));
   --  Short-circuit: the right operand is evaluated only when needed.
   if Divisor /= 0 and then A / Divisor > 1 then
      Put_Line ("never printed");
   else
      Put_Line ("and then avoided dividing by zero");
   end if;
   Put_Line ("""Ada"" < ""Adb"" = " & Boolean'Image (Word < "Adb"));
   Put_Line ("Concatenation  : " & Word & " " & "2022");
   Put_Line ("True xor True  = " & Boolean'Image (True xor True));
end L10_Ops;