Ada Resource Association
News and resources for the Ada programming language
Annotated Ada Reference ManualLegal Information
Contents   Index   References   Search   Previous   Next 

4.5.2 Relational Operators and Membership Tests

[{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.
Ramification: The equality operators are not defined for every nonlimited type — see below for the exact rule. 
{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

{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.
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.
{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

For a membership test, if the 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.

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 : Treturn Boolean
function "/="(Left, Right : Treturn 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_accessreturn Boolean
function "/="(Left, Right : universal_accessreturn 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 : Treturn Boolean
function "<="(Left, Right : Treturn Boolean
function ">" (Left, Right : Treturn Boolean
function ">="(Left, Right : Treturn 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: 
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 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

  {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: 
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

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. {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.] 
Reason: This allows each Access attribute_reference for a subprogram to designate a distinct “wrapper” subprogram if necessary to support an indirect call. 
{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. 
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;
   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. 
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.
{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: 
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: 
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. 
Ramification: Two null arrays of the same type are always equal; two null records of the same type are always equal.
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.
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).
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 "=".
   {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]}
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.
{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).
{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.
A membership test using in yields the result True if: 
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.
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. 
Ramification: Note that the tag is not checked if the simple_expression is of a specific type. 
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: 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. 
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.
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 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
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

{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} {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

{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.

Contents   Index   References   Search   Previous   Next 
Ada-Europe Sponsored by Ada-Europe