4.5.2 Relational Operators and Membership Tests
1
[
{relational operator} 
{operator (relational)} 
{comparison operator: 
See relational operator} {equality 
operator} {operator 
(equality)} The 
equality operators 
= (equals) and /= (not equals) are predefined for nonlimited types. 
{ordering 
operator} {operator 
(ordering)} The other 
relational_operators 
are the 
ordering operators < (less than), <= (less than 
or equal), > (greater than), and >= (greater than or equal). 
{= 
operator} {operator 
(=)} {equal 
operator} {operator 
(equal)} {/= 
operator} {operator 
(/=)} {not 
equal operator} {operator 
(not equal)} {< 
operator} {operator 
(<)} {less 
than operator} {operator 
(less than)} {<= 
operator} {operator 
(<=)} {less 
than or equal operator} {operator 
(less than or equal)} {> 
operator} {operator 
(>)} {greater 
than operator} {operator 
(greater than)} {>= 
operator} {operator 
(>=)} {greater 
than or equal operator} {operator 
(greater than or equal)} {discrete 
array type} The ordering operators are 
predefined for scalar types, and for 
discrete array types, that 
is, one-dimensional array types whose components are of a discrete type. 
 
1.a
Ramification: The equality operators 
are not defined for every nonlimited type — see below for 
the exact rule. 
2
{membership test} 
{in (membership test)} 
{not in (membership 
test)} A 
membership test, using 
in or 
not in, determines whether or not a value belongs 
to a given subtype or range, or has a tag that identifies a type that 
is covered by a given type. Membership tests are allowed for all types.]
 
Name Resolution Rules
3/2
{
AI95-00251-01} 
{expected type (membership test simple_expression) 
[partial]} {tested 
type (of a membership test)} The 
tested 
type of a membership test is the type of the 
range 
or the type determined by the 
subtype_mark. 
If the tested type is tagged, then the 
simple_expression 
shall resolve to be of a type that 
is convertible 
(see 4.6) to covers 
or is covered by the tested type; if untagged, the expected type 
for the 
simple_expression is the tested type.
 
3.a/2
Reason: {
AI95-00230-01} 
The part of the rule for untagged types is stated in a way that ensures 
that operands like 
a string literal null 
are still legal as operands of a membership test.
 
3.b/2
{
AI95-00251-01} 
The significance of “
is convertible to covers 
or is covered by” is that we allow the 
simple_expression 
to be of any class-wide type that 
could be converted 
to covers the tested type, not just 
the one rooted at the tested type.
 This includes 
any class-wide type that covers the tested type, along with class-wide 
interfaces in some cases.  
Legality Rules
4
For a membership test, if the simple_expression 
is of a tagged class-wide type, then the tested type shall be (visibly) 
tagged. 
4.a
Ramification: Untagged types covered 
by the tagged class-wide type are not permitted. Such types can exist 
if they are descendants of a private type whose full type is tagged. 
This rule is intended to avoid confusion since such derivatives don't 
have their “own” tag, and hence are indistinguishable from 
one another at run time once converted to a covering class-wide type. 
Static Semantics
5
The result type of a membership test is the predefined 
type Boolean.
6
The equality operators 
are predefined for every specific type T that is not limited, 
and not an anonymous access type, with the following specifications: 
7
function "=" (Left, Right : T) return Boolean
function "/="(Left, Right : T) return Boolean
7.1/2
  {
AI95-00230-01} 
The following additional equality operators for 
the universal_access type are declared in package Standard for 
use with anonymous access types:  
7.2/2
function "=" (Left, Right : universal_access) return Boolean
function "/="(Left, Right : universal_access) return Boolean
8
The ordering operators 
are predefined for every specific scalar type T, and for every 
discrete array type T, with the following specifications: 
9
function "<" (Left, Right : T) return Boolean
function "<="(Left, Right : T) return Boolean
function ">" (Left, Right : T) return Boolean
function ">="(Left, Right : T) return Boolean
Name Resolution Rules
9.1/2
  {
AI95-00230-01} 
{
AI95-00420-01} 
At least one of the operands of an equality operator 
for universal_access shall be of a specific anonymous access type. 
Unless the predefined equality operator is identified using an expanded 
name with prefix denoting the package Standard, 
neither operand shall be of an access-to-object type whose designated 
type is D or D'Class, where D has a user-defined 
primitive equality operator such that:  
9.2/2
- its result type 
is Boolean;
 
9.3/2
- it is declared 
immediately within the same declaration list as D; and
 
9.4/2
- at least one 
of its operands is an access parameter with designated type D. 
 
9.a/2
Reason: The first 
sentence prevents compatibility problems by ensuring that these operators 
are not used for named access types. Also, universal access types do 
not count for the purposes of this rule. Otherwise, equality expressions 
like (X = null) would be ambiguous for normal access types.
9.b/2
The rest of the rule makes 
it possible to call (including a dispatching call) user-defined "=" 
operators for anonymous access-to-object types (they'd be hidden otherwise), 
and to write user-defined "=" operations for anonymous access 
types (by making it possible to see the universal operator using the 
Standard prefix). 
9.c/2
Ramification: We 
don't need a similar rule for anonymous access-to-subprogram types because 
they can't be primitive for any type. Note that any non-primitive user-defined 
equality operators still are hidden by the universal operators; they'll 
have to be called with a package prefix, but they are likely to be very 
uncommon. 
Legality Rules
9.5/2
  {
AI95-00230-01} 
At least one of the operands of the equality operators 
for universal_access shall be of type universal_access, 
or both shall be of access-to-object types, or both shall be of access-to-subprogram 
types. Further:  
9.6/2
- When both are 
of access-to-object types, the designated types shall be the same or 
one shall cover the other, and if the designated types are elementary 
or array types, then the designated subtypes shall statically match;
 
9.7/2
- When both are 
of access-to-subprogram types, the designated profiles shall be subtype 
conformant. 
 
9.d/2
Reason: We don't 
want to allow completely arbitrary comparisons, as we don't want to insist 
that all access types are represented in ways that are convertible to 
one another. For instance, a compiler could use completely separate address 
spaces or incompatible representations. Instead, we allow compares if 
there exists an access parameter to which both operands could be converted. 
Since the user could write such an subprogram, and any reasonable meaning 
for "=" would allow using it in such a subprogram, this doesn't 
impose any further restrictions on Ada implementations. 
Dynamic Semantics
10
For discrete types, the predefined relational operators 
are defined in terms of corresponding mathematical operations on the 
position numbers of the values of the operands.
11
For real types, the predefined relational operators 
are defined in terms of the corresponding mathematical operations on 
the values of the operands, subject to the accuracy of the type. 
11.a
Ramification: For floating point types, 
the results of comparing 
nearly equal values depends on the accuracy 
of the implementation (see 
G.2.1, “
Model 
of Floating Point Arithmetic” for implementations that support 
the Numerics Annex). 
 
11.b
Implementation Note: On a machine with 
signed zeros, if the generated code generates both plus zero and minus 
zero, plus and minus zero must be equal by the predefined equality operators. 
12
Two access-to-object values are equal if they designate 
the same object, or if both are equal to the null value of the access 
type.
13
Two access-to-subprogram values are equal if they 
are the result of the same evaluation of an Access 
attribute_reference, 
or if both are equal to the null value of the access type. Two access-to-subprogram 
values are unequal if they designate different subprograms. 
{unspecified 
[partial]} [It is unspecified whether two 
access values that designate the same subprogram but are the result of 
distinct evaluations of Access 
attribute_references 
are equal or unequal.] 
 
13.a
Reason: This allows each Access attribute_reference 
for a subprogram to designate a distinct “wrapper” subprogram 
if necessary to support an indirect call. 
14
{equality operator 
(special inheritance rule for tagged types)} For 
a type extension, predefined equality is defined in terms of the primitive 
[(possibly user-defined)] equals operator of the parent type and of any 
tagged components of the extension part, and predefined equality for 
any other components not inherited from the parent type. 
 
14.a
Ramification: Two values of a type extension 
are not equal if there is a variant_part in 
the extension part and the two values have different variants 
present. This is a ramification of the requirement that a discriminant 
governing such a variant_part has to be a 
“new” discriminant, and so has to be equal in the two values 
for the values to be equal. Note that variant_parts 
in the parent part need not match if the primitive equals operator for 
the parent type considers them equal.
14.b/2
{
AI95-00349-01} 
The full type extension's operation is used for 
a private extension. This follows as only full types have parent types; 
the type specified in a private extension is an ancestor, but not necessarily 
the parent type. For instance, in:  
14.c/2
with Pak1;
package Pak2 is
   type Typ3 is new Pak1.Typ1 with private;
private
   type Typ3 is new Pak1.Typ2 with null record;
end Pak2;
  
14.d/2
the parent type is Pak1.Typ2, 
not Pak1.Typ1, and the equality operator of Pak1.Typ2 is used to create 
predefined equality for Typ3. 
15
For a private type, if its full type is tagged, predefined 
equality is defined in terms of the primitive equals operator of the 
full type; if the full type is untagged, predefined equality for the 
private type is that of its full type.
16
{matching 
components} For other composite types, 
the predefined equality operators [(and certain other predefined operations 
on composite types — see 
4.5.1 and 
4.6)] are defined in terms of the corresponding 
operation on 
matching components, defined as follows: 
 
17
- For two composite objects or values 
of the same non-array type, matching components are those that correspond 
to the same component_declaration or discriminant_specification;
 
18
- For two one-dimensional arrays of 
the same type, matching components are those (if any) whose index values 
match in the following sense: the lower bounds of the index ranges are 
defined to match, and the successors of matching indices are defined 
to match;
 
19
- For two multidimensional arrays of 
the same type, matching components are those whose index values match 
in successive index positions. 
 
20
The analogous definitions apply if the types of the 
two objects or values are convertible, rather than being the same. 
20.a
Discussion: Ada 83 seems to omit this 
part of the definition, though it is used in array type conversions. 
See 
4.6. 
 
21
Given the above definition 
of matching components, the result of the predefined equals operator 
for composite types (other than for those composite types covered earlier) 
is defined as follows: 
22
- If there are no components, the result 
is defined to be True;
 
23
- If there are unmatched components, 
the result is defined to be False;
 
24
- Otherwise, the result is defined in 
terms of the primitive equals operator for any matching tagged components, 
and the predefined equals for any matching untagged components. 
 
24.a
Reason: This asymmetry between tagged 
and untagged components is necessary to preserve upward compatibility 
and corresponds with the corresponding situation with generics, where 
the predefined operations “reemerge” in a generic for untagged 
types, but do not for tagged types. Also, only tagged types support user-defined 
assignment (see 
7.6), so only tagged types 
can fully handle levels of indirection in the implementation of the type. 
For untagged types, one reason for a user-defined equals operator might 
be to allow values with different bounds or discriminants to compare 
equal in certain cases. When such values are matching components, the 
bounds or discriminants will necessarily match anyway if the discriminants 
of the enclosing values match. 
 
24.b
Ramification: Two null arrays of the 
same type are always equal; two null records of the same type are always 
equal.
24.c
Note that if a composite object has a component 
of a floating point type, and the floating point type has both a plus 
and minus zero, which are considered equal by the predefined equality, 
then a block compare cannot be used for the predefined composite equality. 
Of course, with user-defined equals operators for tagged components, 
a block compare breaks down anyway, so this is not the only special case 
that requires component-by-component comparisons. On a one's complement 
machine, a similar situation might occur for integer types, since one's 
complement machines typically have both a plus and minus (integer) zero. 
24.d/2
To be honest: {
AI95-00230-01} 
For a component with an anonymous access type, 
“predefined equality” is that defined for the universal_access 
type (anonymous access types have no equality operators of their own). 
24.e/2
For a component with a 
tagged type T, “the primitive equals operator” is 
the one with two parameters of T which returns Boolean. We're 
not talking about some random other primitive function named "=". 
24.1/1
   {
8652/0016} 
{
AI95-00123-01} 
For any composite type, the order in which "=" 
is called for components is unspecified. Furthermore, if the result can 
be determined before calling "=" on some components, it is 
unspecified whether "=" is called on those components.{Unspecified 
[partial]}  
25
The predefined "/=" operator gives the 
complementary result to the predefined "=" operator. 
25.a
Ramification: Furthermore, if the user 
defines an "=" operator that returns Boolean, then a "/=" 
operator is implicitly declared in terms of the user-defined "=" 
operator so as to give the complementary result. See 
6.6. 
 
26
{lexicographic order} 
For a discrete array type, the predefined ordering 
operators correspond to 
lexicographic order using the predefined 
order relation of the component type: A null array is lexicographically 
less than any array having at least one component. In the case of nonnull 
arrays, the left operand is lexicographically less than the right operand 
if the first component of the left operand is less than that of the right; 
otherwise the left operand is lexicographically less than the right operand 
only if their first components are equal and the tail of the left operand 
is lexicographically less than that of the right (the 
tail consists 
of the remaining components beyond the first and can be null).
 
27
{evaluation (membership 
test) [partial]} For the evaluation of 
a membership test, the 
simple_expression and 
the 
range (if any) are evaluated in an arbitrary 
order.
 
28
A membership test using 
in yields the result True if: 
29
- The tested type is scalar, and the 
value of the simple_expression belongs to 
the given range, or the range of the named 
subtype; or 
 
29.a
Ramification: The scalar membership test 
only does a range check. It does not perform any other check, such as 
whether a value falls in a “hole” of a “holey” 
enumeration type. The Pos attribute function can be used for that purpose.
29.b
Even though Standard.Float is an unconstrained 
subtype, the test “X in Float” will still return False (presuming 
the evaluation of X does not raise Constraint_Error) when X is outside 
Float'Range. 
30/2
- {AI95-00231-01} 
The tested type is not scalar, and the value 
of the simple_expression satisfies any constraints 
of the named subtype, and:, 
if the type of the simple_expression is class-wide, 
the value has a tag that identifies a type covered by the tested type. 
 
30.1/2
- {AI95-00231-01} 
if the type of the simple_expression 
is class-wide, the value has a tag that identifies a type covered by 
the tested type; 
 
30.a
Ramification: Note that the tag is not 
checked if the simple_expression is of a specific 
type. 
30.2/2
- {AI95-00231-01} 
if the tested type is an access type and the named 
subtype excludes null, the value of the simple_expression 
is not null. 
 
31
Otherwise the test yields the result False.
32
A membership test using not in gives the complementary 
result to the corresponding membership test using in. 
Implementation Requirements
32.1/1
   {
8652/0016} 
{
AI95-00123-01} 
For all nonlimited types declared in language-defined 
packages, the "=" and "/=" operators of the type 
shall behave as if they were the predefined equality operators for the 
purposes of the equality of composite types and generic formal types. 
 
32.a.1/1
Ramification: If 
any language-defined types are implemented with a user-defined "=" 
operator, then either the full type must be tagged, or the compiler must 
use “magic” to implement equality for this type. A normal 
user-defined "=" operator for an untagged type does not 
meet this requirement. 
33/2
This paragraph was 
deleted.13  {
AI95-00230-01} 
No exception is ever raised by a membership test, 
by a predefined ordering operator, or by a predefined equality operator 
for an elementary type, but an exception can be raised by the evaluation 
of the operands. A predefined equality operator for a composite type 
can only raise an exception if the type has a tagged part whose primitive 
equals operator propagates an exception. 
34
14  If a composite type has components that 
depend on discriminants, two values of this type have matching components 
if and only if their discriminants are equal. Two nonnull arrays have 
matching components if and only if the length of each dimension is the 
same for both. 
Examples
35
Examples of expressions 
involving relational operators and membership tests: 
36
X /= Y
37
"" < "A" and "A" < "Aa"     --  True
"Aa" < "B" and "A" < "A  "  --  True
38
My_Car = 
null               --
 true if My_Car has been set to null (see 3.10.1)
My_Car = Your_Car           --
 true if we both share the same car
My_Car.
all = Your_Car.
all   --
 true if the two cars are identical 
39
N 
not in 1 .. 10            --
 range membership test
Today 
in Mon .. Fri         --
 range membership test
Today 
in Weekday            --
 subtype membership test (see 3.5.1)
Archive 
in Disk_Unit        --
 subtype membership test (see 3.8.1)
Tree.
all in Addition'Class  --
 class membership test (see 3.9.1) 
Extensions to Ada 83
39.a
{
extensions to Ada 83} 
Membership 
tests can be used to test the tag of a class-wide value.
 
39.b
Predefined equality for a composite type is 
defined in terms of the primitive equals operator for tagged components 
or the parent part. 
Wording Changes from Ada 83
39.c
The term “membership test” refers 
to the relation "X in S" rather 
to simply the reserved word in or not in.
39.d
We use the term “equality operator” 
to refer to both the = (equals) and /= (not equals) operators. Ada 83 
referred to = as the equality operator, and /= as the inequality 
operator. The new wording is more consistent with the ISO 10646 name 
for "=" (equals sign) and provides a category similar to “ordering 
operator” to refer to both = and /=.
39.e
We have changed the term “catenate” 
to “concatenate”. 
Extensions to Ada 95
39.f/2
{
AI95-00230-01} 
{
AI95-00420-01} 
{extensions to Ada 95} The 
universal_access equality operators are new. They provide equality 
operations (most importantly, testing against null) for anonymous 
access types.  
Wording Changes from Ada 95
39.g/2
{
8652/0016} 
{
AI95-00123-01} 
Corrigendum: Wording was added to clarify 
that the order of calls (and whether the calls are made at all) on "=" 
for components is unspecified. Also clarified that "=" must 
compose properly for language-defined types. 
39.h/2
{
AI95-00251-01} 
Memberships were adjusted to allow interfaces which 
don't cover the tested type, in order to be consistent with type conversions.