4.5.2 Relational Operators and Membership Tests
= (equals) and /= (not equals) are predefined
for nonlimited types.
are the ordering operators
< (less than), <= (less than
or equal), > (greater than), and >= (greater than or equal).
ordering operators are predefined for scalar types, and for discrete
, that is, one-dimensional array types whose components
are of a discrete type.
Ramification: The equality operators
are not defined for every nonlimited type — see below for
the exact rule.
, using in
or not in
, determines whether or not
a value belongs to any a
given subtype or range, is equal to any given value, or
has a tag that identifies a type that is covered by a given type,
or is convertible to and with accessibility level appropriate for a given
. Membership tests are allowed for all types.]
Name Resolution Rules
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.
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
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.
The special rule for determining the tested type
for elementary types is to allow numeric literals in membership_choice_lists.
Without the rule, A in B | 1 would be illegal as B and
1 would have different types (the literal having type universal integer).
For a membership test, if the simple_expression
is of a tagged class-wide type, then the tested type shall be (visibly)
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.
If a membership test includes one or more choice_expressions
and the tested type of the membership test is limited, then the tested
type of the membership test shall have a visible primitive equality operator.
A visible equality operator is required in order
to avoid breaking privacy; that is, we don't want to depend on a hidden
The result type of a membership test is the predefined
The equality operators
are predefined for every specific type T that is not limited,
and not an anonymous access type, with the following specifications:
function "=" (Left, Right : T) return Boolean
function "/="(Left, Right : T) return Boolean
The following additional equality operators for
the universal_access type are declared in package Standard for
use with anonymous access types:
function "=" (Left, Right : universal_access) return Boolean
function "/="(Left, Right : universal_access) return Boolean
The ordering operators
are predefined for every specific scalar type T, and for every
discrete array type T, with the following specifications:
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
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:
its result type is Boolean;
it is declared immediately within the same declaration
list as D or any partial or incomplete
view of D; and
at least one of its operands
is an access parameter with designated type D.
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.
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
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
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
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;
When both are of access-to-subprogram
types, the designated profiles shall be subtype conformant.
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.
If the profile of an explicitly declared primitive
equality operator of an untagged record type is type conformant with
that of the corresponding predefined equality operator, the declaration
shall occur before the type is frozen. In addition, if the untagged record
type has a nonlimited partial view, then the declaration shall occur
in the visible part of the enclosing package. In
addition to the places where Legality Rules normally apply (see 12.3),
this rule applies also in the private part of an instance of a generic
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.
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.
For floating point types,
the results of comparing nearly
equal values depends on the accuracy
of the implementation (see G.2.1
of Floating Point Arithmetic
” for implementations that support
the Numerics Annex).
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.
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
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.
is unspecified whether two access values that designate the same subprogram
but are the result of distinct evaluations of Access attribute_reference
are equal or unequal.]
This allows each Access attribute_reference
for a subprogram to designate a distinct “wrapper” subprogram
if necessary to support an indirect call.
For a type extension, predefined equality is defined
in terms of the primitive [(possibly user-defined)] equals operator for of
the parent type and for of
components that have a record type in of
extension part, and predefined equality for any other components not
inherited from the parent type.
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 variant
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_part
in the parent part need not match if the primitive equals operator for
the parent type considers them equal.
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:
package Pak2 is
type Typ3 is new Pak1.Typ1 with private;
type Typ3 is new Pak1.Typ2 with null record;
the parent type is Pak1.Typ2,
not Pak1.Typ1, and the equality operator of Pak1.Typ2 is used to create
predefined equality for Typ3.
For a derived type whose parent is an untagged
record type, predefined equality is defined in terms of the primitive
(possibly user-defined) equals operator of the parent type.
Reason: This prevents
predefined equality from reemerging in generic units for untagged record
types. For other uses the primitive equality is inherited and the inherited
routine is primitive.
For a private type, if its full type is a record
, predefined equality
is defined in terms of the primitive equals operator of the full type;
otherwise if the full
type is untagged
, predefined equality for the private type is
that of its full type.
other composite types, the predefined equality operators [(and certain
other predefined operations on composite types — see 4.5.1
)] are defined in terms of the corresponding
operation on matching components
, defined as follows:
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;
For two multidimensional arrays of the same type,
matching components are those whose index values match in successive
The analogous definitions apply if the types of the
two objects or values are convertible, rather than being the same.
Ada 83 seems to omit this
part of the definition, though it is used in array type conversions.
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:
If there are no components, the result is defined
to be True;
If there are unmatched components, the result is
defined to be False;
Otherwise, the result is defined in terms of the primitive equals operator
for any matching tagged
components that are records
, and the predefined equals for any other
This asymmetry between tagged and untagged
with and without a record type
to preserve most
upward compatibility and
corresponds with the corresponding situation with generics, where the
predefined operations “reemerge” in a generic for non-record untagged
types, but do not for record 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.
Ramification: Two null arrays of the
same type are always equal; two null records of the same type are always
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 that are records
, 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.
To be honest:
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).
For a component with a record 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 "=".
If the primitive equals operator for an untagged
record type is abstract, then Program_Error is raised at the point of
any (implicit) call to that abstract subprogram.
Reason: An explicit
call to an abstract subprogram is illegal. This rule is needed in order
to define the effect of an implicit call such as a call that is part
of the predefined equality operation for an enclosing composite type
that has a component of an untagged record type that has an abstract
primitive equals operator. For tagged types, an abstract primitive equals
operator is only allowed for an abstract type, and abstract types cannot
be components, so this case does not occur.
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.
The predefined "/=" operator gives the
complementary result to the predefined "=" operator.
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
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;
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).
This equivalence includes the evaluation of the
evaluation stops as soon as an individual choice evaluates to True.
An individual membership test A
membership test using in
yields the result True if:
The scalar membership test only does a range check and a predicate 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.
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
Note that the tag is not
checked if the simple_expression
is of a specific type.
if the tested type is a general access-to-object
type, the type of the simple_expression
is convertible to the tested type and its accessibility level is no deeper
than that of the tested type; further, if the designated type is tagged
and the simple_expression
is non-null, the tag of the object designated by the value of the simple_expression
is covered by the designated type of the tested type.
the test yields the result False.
A membership test using not in gives the complementary
result to the corresponding membership test using in.
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.
If any language-defined types are implemented with
a user-defined "=" operator, then either the full type must
be a record type tagged,
or the compiler must use “magic” to implement equality for
this type. A normal user-defined "=" operator for a
untagged type does not meet
This paragraph was
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.
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 of expressions
involving relational operators and membership tests:
X /= Y
"" < "A" and "A" < "Aa" -- True
"Aa" < "B" and "A" < "A " -- True
My_Car = null
-- True true if My_Car has been set to null (see 3.10.1)
My_Car = Your_Car -- True true if we both share the same car
-- True true if the two cars are identical
N not in
1 .. 10 -- range membership test
Mon .. Fri -- range membership test
Weekday -- subtype membership test (see 3.5.1)
Card in Clubs | Spades -- list membership test (see 3.5.1)
Disk_Unit -- subtype membership test (see 3.8.1)
Addition'Class -- class membership test (see 3.9.1)
Extensions to Ada 83
Membership tests can be
used to test the tag of a class-wide value.
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
The term “membership test” refers
to the relation
"X in S" rather to simply the reserved word in
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 /=.
We have changed the term “catenate”
Extensions to Ada 95
equality operators are new. They provide equality operations (most importantly,
testing against null) for anonymous access types.
Wording Changes from Ada 95
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.
Memberships were adjusted to allow interfaces which
don't cover the tested type, in order to be consistent with type conversions.
Inconsistencies With Ada 2005
User-defined untagged record
equality is now defined to compose and be used in generics. Any code
which assumes that the predefined equality reemerges in generics and
in predefined equals for composite types could fail. However, it is much
more likely that this change will fix bugs, as the behavior that would
be expected (the user-defined "=" is used) will be true in
If a composite type contains a component of an
untagged record type with an abstract equality operation, calling "="
on the composite type will raise Program_Error, while in the past a result
will be returned using the predefined equality. This is quite possible
in ASIS programs; it will detect a bug in such programs but of course
the programs will need to be fixed before they will work.
Incompatibilities With Ada 2005
Late and hidden overriding
of equality for untagged record types is now prohibited. This is necessary
to make composition of equality predictable. It should always be possible
to move the overriding to an earlier spot where it will be legal.
Extensions to Ada 2005
Membership tests for the accessibility
and designated tags for general access types are new.
Membership tests now include a predicate check.
Membership tests now allow multiple choices.
Wording Changes from Ada 2005
Correction: Wording was added to clarify
that universal_access "=" does not apply if an appropriate
operator is declared for a partial or incomplete view of the designated
type. Otherwise, adding a partial or incomplete view could make some
"=" operators ambiguous.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe