Operators in Ada
Master arithmetic, relational, logical, and string operators in Ada, including its uniquely safe approach to type-distinct arithmetic and operator overloading
Operators in Ada are the building blocks of every expression, from a simple counter increment to the complex calculations behind avionics control loops. Where languages like C silently mix integers and floats, Ada treats operators as strongly-typed subprograms — 1 + 1.0 is a compile-time error, not an implicit conversion. This safety-first design is one of the reasons Ada code can be trusted in flight control systems for decades.
As a statically and strongly typed language, Ada distinguishes carefully between operators on different numeric types. Integer division (/) truncates toward zero, mod and rem differ in their treatment of negative operands, and the exponentiation operator (**) is built into the language rather than relegated to a standard-library function. Equally important, every operator in Ada is really just a function — and you can overload them yourself for your own types.
This tutorial walks through the full set of Ada operators with runnable examples. You will see arithmetic on integers and floats, relational comparisons, short-circuit boolean logic, bitwise-style operations on modular types, string concatenation, and Ada’s distinctive mod vs. rem distinction.
Arithmetic Operators
Ada provides the familiar +, -, *, /, plus mod, rem, and ** (exponentiation). Crucially, the operands must have the same type — there is no implicit promotion from Integer to Float.
Create a file named arithmetic.adb:
| |
Two things stand out. First, integer division 17 / 5 truncates to 3 — no automatic float promotion. Second, 2 ** 10 is built into the language; you do not need to import a math package for exponentiation.
mod vs. rem: A Subtle Distinction
Ada is one of the few mainstream languages that provides both mod and rem. They differ only when the operands have different signs.
Create a file named mod_rem.adb:
| |
The rule: rem takes the sign of the dividend (the left operand), while mod takes the sign of the divisor (the right operand). For positive operands they agree, but for negatives they differ — and for clock-style arithmetic where you want a non-negative result, mod is almost always what you want.
Relational and Logical Operators
Ada uses = and /= for equality and inequality (not == and !=), plus the usual <, <=, >, >=. Boolean operators come in two flavors: the regular and/or always evaluate both operands, while and then/or else short-circuit — they stop as soon as the result is determined.
Create a file named logical.adb:
| |
The Ada Reference Manual deliberately forbids mixing and and or in the same expression without parentheses — for example, A and B or C is a syntax error. This forces you to write explicit grouping, eliminating an entire class of precedence bugs.
String Concatenation and Membership
Ada uses & for string (and array) concatenation, and the in / not in operators for range and membership tests — extremely handy for input validation.
Create a file named strings_membership.adb:
| |
The in operator paired with a range (0 .. 100) or a set of alternatives (90 .. 100 | 80 .. 89) is a far cleaner way to express bounds checks than chains of >= and <=. Ada’s type system uses the same syntax to define range-constrained types like type Percentage is range 0 .. 100;.
Operator Overloading
Every operator in Ada is a function in disguise — A + B is sugar for "+"(A, B). This means you can define your own operators for your own types, which is essential for unit-safe arithmetic.
Create a file named overload.adb:
| |
Because Meters is a distinct type derived from Float, the compiler treats Meters + Meters as a different operator from Float + Float. Attempting Distance_A + 7.5 (a raw Float) would not compile — exactly the kind of error that contributed to the loss of the Mars Climate Orbiter.
Running with Docker
| |
Expected Output
Running arithmetic:
Integer arithmetic:
17 + 5 = 22
17 - 5 = 12
17 * 5 = 85
17 / 5 = 3
17 mod 5 = 2
17 rem 5 = 2
2 ** 10 = 1024
Float arithmetic:
17.0 / 5.0 = 3.40
Running mod_rem:
A = 13 B = 5 A mod B = 3 A rem B = 3
A = -13 B = 5 A mod B = 2 A rem B = -3
A = 13 B = -5 A mod B = -2 A rem B = 3
A = -13 B = -5 A mod B = -3 A rem B = -3
Running logical:
Relational results:
Age = 25, Age >= 18 -> TRUE
10 /= 10 -> FALSE
'A' < 'B' -> TRUE
Boolean combinators:
Has_ID and Is_Adult -> TRUE
Has_ID and then Is_Adult -> TRUE
False or else (1 / 0 > 0) -> short-circuit avoids divide-by-zero
not Is_Adult -> FALSE
True xor False -> TRUE
Running strings_membership:
Concatenated: Ada Lovelace
Length: 12
87 is a valid percentage
Grade: A or B
Passing grade
Running overload:
A = 1.25000E+01 m
B = 7.50000E+00 m
A + B = 2.00000E+01 m
Operator Precedence
Ada groups operators into six precedence levels, from highest to lowest:
| Level | Operators | Notes |
|---|---|---|
| 1 (highest) | **, abs, not | Exponentiation and unary |
| 2 | *, /, mod, rem | Multiplying |
| 3 | unary +, - | Sign |
| 4 | binary +, -, & | Adding and concatenation |
| 5 | =, /=, <, <=, >, >=, in, not in | Relational |
| 6 (lowest) | and, or, xor, and then, or else | Logical |
Because and and or share the lowest level and cannot be mixed without parentheses, expressions like A and B and C are fine but A and B or C requires explicit grouping: (A and B) or C.
Key Concepts
- Strong typing applies to operators: mixed-type expressions like
1 + 1.0are compile errors; convert explicitly withFloat (1) + 1.0. modvs.rem:remfollows the dividend’s sign,modfollows the divisor’s — usemodfor wraparound-style arithmetic.**is built-in: integer and float exponentiation needs no library import.- Short-circuit forms are explicit:
and then/or elseshort-circuit,and/oralways evaluate both sides. xoris a first-class logical operator, and mixingandwithorwithout parentheses is forbidden by the syntax — a built-in defense against precedence bugs.inandnot intest ranges and membership cleanly:X in 0 .. 100beatsX >= 0 and X <= 100.&concatenates strings and arrays; it has lower precedence than arithmetic but higher than comparison.- Every operator is overloadable: define
function "+" (L, R : My_Type) return My_Typeto give your own types arithmetic.
Running Today
All examples can be run using Docker:
docker pull codearchaeology/ada:latest
Comments
Loading comments...
Leave a Comment