Ada: Expressions
An expression combines literals, names, function calls, and operators to compute one value of one type. Ada's twist is that the type system follows the expression everywhere: arithmetic operators never silently convert, mixing types in one expression is a compile error, and every operator is overloaded per type.
Operators and Precedence
Ada has six precedence classes, from highest to lowest:
| Class | Operators | Example |
|---|---|---|
| Highest (unary) | abs, not, ** | -X, abs X, 2 ** 10 |
| Multiplying | *, /, mod, rem | A * B, X mod 10 |
| Binary adding | +, -, & | A + B, First & Last |
| Relational | =, /=, <, <=, >, >= | A /= B (note: /= means "not equal") |
| Logical (short circuit) | and then, or else | Present and then Valid |
| Logical | and, or, xor, in, not in | N in 1 .. 10 |
Two operators deserve immediate attention because they encode decisions most languages leave unsafe:
and thenshort-circuits: if the left side is False the right side is never evaluated. Use it whenever the right side would crash on invalid input.intests membership in a range or subtype — the natural spelling of validation.
Integer Division and Remainders
Ada distinguishes mod (result has the sign of the divisor) from rem (sign of the dividend). Both are total: division by zero raises Constraint_Error, there is no undefined behavior:
with Ada.Text_IO; use Ada.Text_IO;
procedure Remainder_Demo is
begin
Put_Line (Integer'Image (7 mod 3)); -- 1 sign of divisor (+)
Put_Line (Integer'Image ((-7) mod 3)); -- 2 wraps up to the divisor's sign
Put_Line (Integer'Image (7 rem 3)); -- 1 sign of dividend (+)
Put_Line (Integer'Image ((-7) rem 3)); -- -1 truncates toward zero
-- Put_Line (Integer'Image (7 / 0)); -- Constraint_Error, never UB
end Remainder_Demo;
If you need the mathematical "wrap around a circle" behavior, mod is always right; rem matches what C's % does.
Type Safety in Expressions
Operators belong to types. + for Integer and + for Float are different overloads, and operands must agree:
procedure Mixing_Demo is
Count : Integer := 3;
Rate : Float := 2.5;
begin
-- declare
-- Bad : Float := Count * Rate; -- compile error: Integer * Float
-- is rejected: the compiler will not guess. State the conversion:
declare
Good : constant Float := Float (Count) * Rate; -- 7.5
begin
null;
end;
end Mixing_Demo;
Universal expressions are the one exception: numeric literals and named numbers can appear on either side because they belong to no type until the context fixes one.
Membership and Ranges
in and not in read like the validation they perform:
with Ada.Text_IO; use Ada.Text_IO;
procedure Membership_Demo is
Reading : constant Integer := 47;
begin
if Reading in 40 .. 80 then -- inclusive range test
Put_Line ("within operating band");
end if;
if Reading not in 1 .. 100 then -- the readable negation
Put_Line ("out of range");
end if;
end Membership_Demo;
Next: Conditionals — turning these expressions into decisions.