4.5.2 Relational Operators and Membership Tests
[
The
equality operators = (equals) and /= (not equals) are predefined
for nonlimited types.
The other
relational_operators
are the
ordering operators < (less than), <= (less than
or equal), > (greater than), and >= (greater than or equal).
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.
Ramification: The equality operators
are not defined for every nonlimited type — see below for
the exact rule.
{
AI05-0262-1}
{
AI05-0269-1}
A
membership
test, using
in or
not in, determines whether or not
a value belongs to any given subtype or range, is equal to any given
value, has a tag that identifies a type that is covered by a given type,
or is convertible to and has an accessibility level appropriate for a
given access type. Membership tests are allowed for all types.]
Name Resolution Rules
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 are still legal as operands of a
membership test.
{
AI95-00251-01}
{
AI12-0039-1}
The significance of “is convertible to” is that we allow
the
tested_simple_expression
to be of any class-wide type that could be converted to 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.
{
AI05-0158-1}
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).
Legality Rules
{
AI12-0039-1}
For a membership test, if the
tested_simple_expression
is of a tagged class-wide type, then the tested type shall be (visibly)
tagged.
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.
{
AI05-0158-1}
{
AI12-0039-1}
{
AI12-0328-1}
If a membership test includes one or more
choice_simple_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;
if the tested type of the membership test is nonlimited with a user-defined
primitive equality operator that is defined at a point where the type
is limited, the tested type shall be a record type or record extension.
Reason: {
AI05-0158-1}
A visible equality operator is required in order to avoid breaking privacy;
that is, we don't want to depend on a hidden equality operator.
{
AI12-0328-1}
We make the membership test on the nonlimited view of a type illegal
if it would use a different equality operator than what would be used
for a limited view of the same type (and such a limited view is known
to exist).
Static Semantics
The result type of a membership test is the predefined
type Boolean.
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
{
AI95-00230-01}
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
{
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:
its result type is Boolean;
{
AI05-0020-1}
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 Standard
prefix).
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 nonprimitive 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
{
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:
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.
{
AI05-0123-1}
{
AI12-0101-1}
{
AI12-0352-1}
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, no type shall have been derived from the
untagged record type before the declaration of the primitive equality
operator.
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 unit.
Dynamic Semantics
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.
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).
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
type.
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.
[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.]
Reason: This allows each Access
attribute_reference
for a subprogram to designate a distinct “wrapper” subprogram
if necessary to support an indirect call.
{
AI05-0123-1}
For a type extension, predefined equality is defined
in terms of the primitive [(possibly user-defined)] equals operator for
the parent type and for any components that have a record type in the
extension part, and predefined equality for any other components not
inherited from the parent type.
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.
{
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:
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;
the parent type is Pak1.Typ2, not Pak1.Typ1,
and the equality operator of Pak1.Typ2 is used to create predefined equality
for Typ3.
{
AI05-0123-1}
{
AI12-0328-1}
For a private type, if its full type is a record type or a record extension,
predefined equality is defined in terms of the primitive equals operator
of the full type; otherwise, predefined equality for the private type
is that of its full type.
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:
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
index positions.
The analogous definitions apply if the types of the
two objects or values are convertible, rather than being the same.
Discussion: Ada 83 seems to omit this
part of the definition, though it is used in array type conversions.
See
4.6.
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;
{
AI05-0123-1}
Otherwise, the result is defined in terms of the primitive equals operator
for any matching components that are records, and the predefined equals
for any other matching components.
Reason: {
AI05-0123-1}
This asymmetry between components with and without a record type is necessary
to preserve most upward compatibility and corresponds with the corresponding
situation with generics, where the predefined operations “reemerge”
in a generic for non-record types, but do not for record 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
equal.
{
AI05-0123-1}
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 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: {
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).
{
AI05-0123-1}
For a component with a record 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 "=".
{
AI05-0123-1}
{
AI12-0413-1}
If the primitive equals operator for an untagged record type is abstract,
then Program_Error is raised at the point of any call to that abstract
subprogram[, implicitly as part of an equality operation on an enclosing
composite object, or in an instance of a generic with a formal private
type where the actual type is a record type with an abstract "="].
Reason: {
AI12-0413-1}
An explicit call to an abstract subprogram is generally illegal. This
rule is needed in order to define the effect of a call in an instance
of a generic body, or 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.
{
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.
The predefined "/=" operator gives the
complementary result to the predefined "=" operator.
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.
{
AI05-0264-1}
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).
Ramification: {
AI05-0158-1}
This equivalence includes the evaluation of the
membership_choices;
evaluation stops as soon as an individual choice evaluates to True.
Reason: We use the predefined equality
operator if the membership test occurs where the type is nonlimited if
the type is not a record type or record extension. However, to avoid
confusion, cases where a membership test could use different equality
operators based on the view are illegal.
Ramification: {
AI05-0153-3}
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
Float'Range.
{
AI05-0149-1}
{
AI12-0039-1}
if the tested type is a general access-to-object type, the type of the
tested_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 of the
tested type is tagged and the
tested_simple_expression
is nonnull, the tag of the object designated by the value of the
tested_simple_expression
is covered by the designated type of the tested type.
To be honest:
{
AI12-0005-1}
In some of these cases, the bulleted checks need to pass before any predicate
check is executed. Otherwise, a predicate check could be performed on
an object of the wrong type. Consider:
type Root is tagged null record;
type Ext is new Root with record Data : Integer; end record;
function Is_Even (Param : Ext) return Boolean is
(Param.Data mod 2 = 0);
subtype Even_Ext is Ext
with Dynamic_Predicate => Is_Even (Even_Ext);
function F (X : Root'Class) return Boolean is
(X in Even_Ext);
Flag : Boolean := F (Root'(null record));
If the predicate check is performed before the
tag check or regardless of the result of that check, Is_Even would be
called on an object that does not have a Data component. Similar cases
can be constructed for general access types.
{
AI05-0264-1}
Otherwise, the test yields the result False.
A membership test using not in gives the complementary
result to the corresponding membership test using in.
Implementation Requirements
{
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.
Ramification: {
AI95-00123-01}
{
AI05-0123-1}
If any language-defined types are implemented with a user-defined "="
operator, then either the full type must be a record type, or the compiler
must use “magic” to implement equality for this type. A normal
user-defined "=" operator for a non-record type does
not
meet this requirement.
NOTE 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
Examples of expressions
involving relational operators and membership tests:
X /= Y
{
AI12-0178-1}
{
AI12-0425-1}
A_String = "A" --
True (see 3.3.1)
"" < A_String
and A_String < "Aa" --
True
A_String < "Bb"
and A_String < "A " --
True
{
AI05-0264-1}
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
{
AI05-0158-1}
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)
Card
in Clubs | Spades --
list 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
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 or
not
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”
to “concatenate”.
Extensions to Ada 95
{
AI95-00230-01}
{
AI95-00420-01}
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
{
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.
{
AI95-00251-01}
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
{
AI05-0123-1}
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 more cases.
{
AI05-0123-1}
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
{
AI05-0123-1}
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
{
AI05-0149-1}
Membership tests for valid accessibility levels and
tag coverage by the designated type for general access types are new.
{
AI05-0153-3}
Membership tests now include a predicate check.
{
AI05-0158-1}
Membership tests now allow multiple choices.
Wording Changes from Ada 2005
{
AI05-0020-1}
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.
Inconsistencies With Ada 2012
{
AI12-0101-1}
Corrigendum: Removed the incompatible rule
preventing the declaration of "=" in the private part of a
package specification for an untagged record type that completes a private
type. Any code that calls the predefined "=" on the private
type will now execute the body for the redefined "=" instead
for the predefined "=". Eliminating the rule eliminates an
unnecessary incompatibility (especially for programs that never call
the predefined "="). Moreover, (like the composition of untagged
record "=" in Ada 2012) this is more likely to fix bugs than
cause them (who defines an "=" with a presumably different
result and does not want clients to use it?).
Incompatibilities With Ada 2012
{
AI12-0328-1}
A membership test is now illegal if all of the following
are True:
The membership test occurs in a place where
the tested type is nonlimited;
The tested type has a limited view with a
primitive "=" operator;
The full type of the tested type is not a
record type or a record extension.
In such a case, the limited and nonlimited views
would use different equality operators, which would be confusing and
would cause various semantic difficulties. We believe such cases to be
quite rare, especially as such membership tests are new to Ada 2012.
The workaround is to replace such memberships with equality tests (assuming
that the primitive "=" is intended; the predefined "="
is hidden in such cases and an extra type is needed to make it accessible).
Wording Changes from Ada 2012
{
AI12-0071-1}
Corrigendum: Updated wording of the membership tests to use the
new term "satisfies the predicates" (see
3.2.4).
{
AI12-0413-1}
Correction: Clarified that a call to an abstract equality in an
instance body raises Program_Error.
Ada 2005 and 2012 Editions sponsored in part by Ada-Europe