Lady Ada

Ada '83 Language Reference Manual

Copyright 1980, 1982, 1983 owned by the United States Government. Direct reproduction and usage requests to the Ada Information Clearinghouse.


4.5. Operators and Expression Evaluation

[PREVIOUS][UP][NEXT]

The language defines the following six classes of operators. The corresponding operator symbols (except /=), and only those, can be used as designators in declarations of functions for user-defined operators. They are given in the order of increasing precedence.

    logical_operator             ::=  and | or  | xor 
    relational_operator          ::=  =   | /=  | <   | <= | > | >= 
    binary_adding_operator       ::=  +   | -   | & 
    unary_adding_operator        ::=  +   | - 
    multiplying_operator         ::=  *   | /   | mod | rem 
    highest_precedence_operator  ::=  **  | abs | not 

The short-circuit control forms and then and or else have the same precedence as logical operators. The membership tests in and not in have the same precedence as relational operators.

For a term, simple expression, relation, or expression, operators of higher precedence are associated with their operands before operators of lower precedence. In this case, for a sequence of operators of the same precedence level, the operators are associated in textual order from left to right; parentheses can be used to impose specific associations.

The operands of a factor, of a term, of a simple expression, or of a relation, and the operands of an expression that does not contain a short-circuit control form, are evaluated in some order that is not defined by the language (but before application of the corresponding operator). The right operand of a short-circuit control form is evaluated if and only if the left operand has a certain value (see 4.5.1).

For each form of type declaration, certain of the above operators are predefined, that is, they are implicitly declared by the type declaration. For each such implicit operator declaration, the names of the parameters are LEFT and RIGHT for binary operators; the single parameter is called RIGHT for unary adding operators and for the unary operators abs and not. The effect of the predefined operators is explained in subsections 4.5.1 through 4.5.7.

The predefined operations on integer types either yield the mathematically correct result or raise the exception NUMERIC_ERROR. A predefined operation that delivers a result of an integer type (other than universal_integer) can only raise the exception NUMERIC_ERROR if the mathematical result is not a value of the type. The predefined operations on real types yield results whose accuracy is defined in section 4.5.7. A predefined operation that delivers a result of a real type (other than universal_real) can only raise the exception NUMERIC_ERROR if the result is not within the range of the safe numbers of the type, as explained in section 4.5.7.

Examples of precedence:

    not SUNNY or WARM    --  same as (not SUNNY) or WARM
    X > 4.0 and Y > 0.0  --  same as (X > 4.0) and (Y > 0.0)    

    -4.0*A**2            --  same as -(4.0 * (A**2))
    abs(1 + A) + B       --  same as (abs (1 + A)) + B
    Y**(-3)              --  parentheses are necessary
    A / B * C            --  same as (A/B)*C
    A + (B + C)          --  evaluate B + C before adding it to A 

References: designator, expression, factor, implicit declaration, in some order, integer type, membership test, name, numeric_error exception, overloading, and 8.7, raising of an exception, range, real type, relation, safe number, short-circuit control form, and 4.5.1, simple expression, term, type, type declaration, universal_integer type, universal_real type.

Rationale references: 3.6 Expressions, 3.8 Assignment Statements - The Ada Model of Time, 3.10 Short-Circuit Control Forms

Style Guide references: 2.1.1 Horizontal Spacing, 2.1.3 Alignment of Operators, 5.5.3 Parenthetical Expressions, 5.7.1 The Use Clause, 5.7.2 The Renames Clause, 5.7.4 Overloaded Operators, 7.2.7 Subexpression Evaluation

Sub-topics:

4.5.1. Logical Operators and Short-circuit Control Forms

[UP][NEXT]

The following logical operators are predefined for any boolean type and any one-dimensional array type whose components are of a boolean type; in either case the two operands have the same type.

Operator  Operation              Operand type                 Result type

and     conjunction            any boolean type             same boolean type
                               array of boolean components  same array type
or      inclusive disjunction  any boolean type             same boolean type
                               array of boolean components  same array type
xor     exclusive disjunction  any boolean type             same boolean type
                               array of boolean components  same array type

The operations on arrays are performed on a component-by-component basis on matching components, if any (as for equality, see 4.5.2). The bounds of the resulting array are those of the left operand. A check is made that for each component of the left operand there is a matching component of the right operand, and vice versa. The exception CONSTRAINT_ERROR is raised if this check fails.

The short-circuit control forms and then and or else are defined for two operands of a boolean type and deliver a result of the same type. The left operand of a short-circuit control form is always evaluated first. If the left operand of an expression with the control form and then evaluates to FALSE, the right operand is not evaluated and the value of the expression is FALSE. If the left operand of an expression with the control form or else evaluates to TRUE, the right operand is not evaluated and the value of the expression is TRUE. If both operands are evaluated, and then delivers the same result as and, and or else delivers the same result as or.

Note:

The conventional meaning of the logical operators is given by the fol- lowing truth table:

    A        B       (A and B)    (A or B)    (A xor B) 

    TRUE    TRUE     TRUE         TRUE        FALSE
    TRUE    FALSE    FALSE        TRUE        TRUE
    FALSE   TRUE     FALSE        TRUE        TRUE
    FALSE   FALSE    FALSE        FALSE       FALSE                                                

Examples of logical operators:

    SUNNY or WARM
    FILTER(1 .. 10) and FILTER(15 .. 24)   --   see 3.6.1 

Examples of short-circuit control forms:

    NEXT_CAR.OWNER /= null and then NEXT_CAR.OWNER.AGE > 25   --   see 3.8.1
    N = 0 or else A(N) = HIT_VALUE 

References: array type, boolean type, bound of an index range, component of an array, constraint_error exception, dimension, false boolean value, index subtype, matching components of arrays, null array, operation, operator, predefined operator, raising of exceptions, true boolean value, type.

Style Guide references: 5.5.4 Positive Forms of Logic, 5.5.5 Short Circuit Forms of the Logical Operators

4.5.2. Relational Operators and Membership Tests

[PREVIOUS][UP][NEXT]

The equality and inequality operators are predefined for any type that is not limited. 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 any scalar type, and for any discrete array type, that is, a one-dimensional array type whose components are of a discrete type. The operands of each predefined relational operator have the same type. The result type is the predefined type BOOLEAN.

The relational operators have their conventional meaning: the result is equal to TRUE if the corresponding relation is satisfied; the result is FALSE otherwise. The inequality operator gives the complementary result to the equality operator: FALSE if equal, TRUE if not equal.

    Operator    Operation                 Operand type          Result type 

    = /=        equality and inequality   any type              BOOLEAN 

    < <= > >=   test for ordering         any scalar type       BOOLEAN
                                          discrete array type   BOOLEAN 
Equality for the discrete types is equality of the values. For real operands whose values are nearly equal, the results of the predefined relational operators are given in section 4.5.7. Two access values are equal either if they designate the same object, or if both are equal to the null value of the access type.

For two array values or two record values of the same type, the left operand is equal to the right operand if and only if for each component of the left operand there is a matching component of the right operand and vice versa; and the values of matching components are equal, as given by the predefined equality operator for the component type. In particular, two null arrays of the same type are always equal; two null records of the same type are always equal.

For comparing two records of the same type, matching components are those which have the same component identifier.

For comparing 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 comparing two multidimensional arrays, matching components are those whose index values match in successive index positions.

If equality is explicitly defined for a limited type, it does not extend to composite types having subcomponents of the limited type (explicit definition of equality is allowed for such composite types).

The ordering operators <, <=, >, and >= that are defined for discrete array types 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).

The membership tests in and not in are predefined for all types. The result type is the predefined type BOOLEAN. For a membership test with a range, the simple expression and the bounds of the range must be of the same scalar type; for a membership test with a type mark, the type of the simple expression must be the base type of the type mark. The evaluation of the membership test in yields the result TRUE if the value of the simple expression is within the given range, or if this value belongs to the subtype denoted by the given type mark; otherwise this evaluation yields the result FALSE (for a value of a real type, see 4.5.7). The membership test not in gives the complementary result to the membership test in.

Examples:

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

    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.7.3)

Notes:

No exception is ever raised by a predefined relational operator or by a membership test, but an exception can be raised by the evaluation of the operands.

If a record 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 value of the attribute LENGTH(N) for each index position N is the same for both.

References: access value, array type, base type, belong to a subtype, boolean predefined type, bound of a range, component, component identifier, component type, composite type, designate, dimension, discrete type, evaluation, exception, index, index range, limited type, null access value, null array, null record, object, operation, operator, predefined operator, raising of exceptions, range, record type, scalar type, simple expression, subcomponent, successor, type, type mark.

Style Guide references: 2.1.1 Horizontal Spacing, 5.5.6 Accuracy of Operations With Real Operands, 5.7.5 Overloading the Equality Operator, 7.2.8 Relational Tests

4.5.3. Binary Adding Operators

[PREVIOUS][UP][NEXT]

The binary adding operators + and - are predefined for any numeric type and have their conventional meaning. The catenation operators & are predefined for any one-dimensional array type that is not limited.

Operator  Operation Left operand type   Right operand type  Result type

 +    addition     any numeric type     same numeric type   same numeric type
 -    subtraction  any numeric type     same numeric type   same numeric type
 &    catenation   any array type       same array type      same array type
                   any array type       the component type   same array type
                   the component type   any array type       same array type
                   the component type   the component type   any array type

For real types, the accuracy of the result is determined by the operand type (see 4.5.7).

If both operands are one-dimensional arrays, the result of the catenation is a one-dimensional array whose length is the sum of the lengths of its operands, and whose components comprise the components of the left operand followed by the components of the right operand. The lower bound of this result is the lower bound of the left operand, unless the left operand is a null array, in which case the result of the catenation is the right operand.

If either operand is of the component type of an array type, the result of the catenation is given by the above rules, using in place of this operand an array having this operand as its only component and having the lower bound of the index subtype of the array type as its lower bound.

The exception CONSTRAINT_ERROR is raised by catenation if the upper bound of the result exceeds the range of the index subtype, unless the result is a null array. This exception is also raised if any operand is of the component type but has a value that does not belong to the component subtype.

Examples:

    Z + 0.1      --  Z must be of a real type 

    "A" & "BCD"  --  catenation of two string literals
    'A' & "BCD"  --  catenation of a character literal and a string literal
    'A' & 'A'    --  catenation of two character literals 

References: array type, character literal, component type, constraint_error exception, dimension, index subtype, length of an array, limited type, null array, numeric type, operation, operator, predefined operator, raising of exceptions, range of an index subtype, real type, string literal, type.

Style Guide references: 2.1.1 Horizontal Spacing, 5.7.4 Overloaded Operators

4.5.4. Unary Adding Operators

[PREVIOUS][UP][NEXT]

The unary adding operators + and - are predefined for any numeric type and have their conventional meaning. For each of these operators, the operand and the result have the same type.

    Operator   Operation   Operand type       Result type 

    +          identity    any numeric type   same numeric type 
    -          negation    any numeric type   same numeric type 

References: numeric type, operation, operator, predefined operator, type.

4.5.5. Multiplying Operators

[PREVIOUS][UP][NEXT]

The operators * and / are predefined for any integer and any floating point type and have their conventional meaning; the operators mod and rem are predefined for any integer type. For each of these operators, the operands and the result have the same base type. For floating point types, the accuracy of the result is determined by the operand type (see 4.5.7).

 Operator     Operation          Operand type           Result type

   *          multiplication     any integer type       same integer type
                                 any floating point     same floating point
                                 type                   type
   /          integer division   any integer type       same integer type
              floating division  any floating point     same floating point
                                 type                   type
  mod         modulus            any integer type       same integer type
  rem         remainder          any integer type       same integer type

Integer division and remainder are defined by the relation

    A = (A/B)*B + (A rem B) 

where (A rem B) has the sign of A and an absolute value less than the absolute value of B. Integer division satisfies the identity

    (-A)/B = -(A/B) = A/(-B) 

The result of the modulus operation is such that (A mod B) has the sign of B and an absolute value less than the absolute value of B; in addition, for some integer value N, this result must satisfy the relation

    A = B*N + (A mod B) 

For each fixed point type, the following multiplication and division operators, with an operand of the predefined type INTEGER, are predefined.

 Operator   Operation   Left operand      Right operand     Result type
                        type              type

   *        multiply    any fixed point   INTEGER           same as left
                        type

                        INTEGER           any fixed point   same as right
                                          type

   /        division    any fixed point   INTEGER           same as left                         
                        type
Integer multiplication of fixed point values is equivalent to repeated addition. Division of a fixed point value by an integer does not involve a change in type but is approximate (see 4.5.7).

Finally, the following multiplication and division operators are declared in the predefined package STANDARD. These two special operators apply to operands of all fixed point types (it is a consequence of other rules that they cannot be renamed or given as generic actual parameters).

Operator  Operation  Left operand      Right operand      Result type
                     type              type

  *       multiply   any fixed point   any fixed point    universal_fixed
                     type              type

  /       divide     any fixed point   any fixed point    universal_fixed
                     type              type

Multiplication of operands of the same or of different fixed point types is exact and delivers a result of the anonymous predefined fixed point type universal_fixed whose delta is arbitrarily small. The result of any such multiplication must always be explicitly converted to some numeric type. This ensures explicit control of the accuracy of the computation. The same considerations apply to division of a fixed point value by another fixed point value. No other operators are defined for the type universal_fixed.

The exception NUMERIC_ERROR is raised by integer division, rem, and mod if the right operand is zero.

Examples:

    I : INTEGER := 1;
    J : INTEGER := 2;
    K : INTEGER := 3; 

    X : REAL digits 6 := 1.0;             --     see 3.5.7
    Y : REAL digits 6 := 2.0; 

    F : FRACTION delta 0.0001  := 0.1;        --     see 3.5.9
    G : FRACTION delta 0.0001  := 0.1;

    Expression        Value     Result Type 

    I*J               2         same as I and J, that is, INTEGER
    K/J               1         same as K and J, that is, INTEGER
    K mod J           1         same as K and J, that is, INTEGER 

    X/Y               0.5       same as X and Y, that is, REAL
    F/2               0.05      same as F, that is, FRACTION 

    3*F               0.3       same as F, that is, FRACTION
    F*G               0.01      universal_fixed, conversion needed
    FRACTION(F*G)     0.01      FRACTION, as stated by the conversion
    REAL(J)*Y         4.0       REAL, the type of both operands after
                                conversion of J                                          

Notes:

For positive A and B, A/B is the quotient and A rem B is the remainder when A is divided by B. The following relations are satisfied by the rem operator:

    A    rem (-B) =   A rem B
    (-A) rem   B  = -(A rem B) 

For any integer K, the following identity holds:

      A  mod   B  =  (A + K*B) mod B 

The relations between integer division, remainder, and modulus are illustrated by the following table:

   A      B   A/B   A rem B  A mod B     A     B    A/B   A rem B   A mod B

   10     5    2       0        0       -10    5    -2       0         0
   11     5    2       1        1       -11    5    -2      -1         4
   12     5    2       2        2       -12    5    -2      -2         3
   13     5    2       3        3       -13    5    -2      -3         2
   14     5    2       4        4       -14    5    -2      -4         1

   10    -5   -2       0        0       -10   -5     2       0         8
   11    -5   -2       1       -4       -11   -5     2      -1        -1
   12    -5   -2       2       -3       -12   -5     2      -2        -2
   13    -5   -2       3       -2       -13   -5     2      -3        -3
   14    -5   -2       4       -1       -14   -5     2      -4        -4

References: actual parameter, base type, declaration, delta of a fixed point type, fixed point type, floating point type, generic formal subprogram, integer type, numeric type, numeric_error exception, predefined operator, raising of exceptions, renaming declaration, standard predefined package, type conversion.

Style Guide references: 9.1.5 Constraint Checking

4.5.6. Highest Precedence Operators

[PREVIOUS][UP][NEXT]

The highest precedence unary operator abs is predefined for any numeric type. The highest precedence unary operator not is predefined for any boolean type and any one-dimensional array type whose components have a boolean type.

 Operator   Operation          Operand type                  Result type

  abs      absolute value     any numeric type              same numeric type

  not      logical negation   any boolean type              same boolean type
                              array of boolean components   same array type

The operator not that applies to a one-dimensional array of boolean components yields a one-dimensional boolean array with the same bounds; each component of the result is obtained by logical negation of the corresponding component of the operand (that is, the component that has the same index value).

The highest precedence exponentiating operator ** is predefined for each integer type and for each floating point type. In either case the right operand, called the exponent, is of the predefined type INTEGER.

 Operator  Operation      Left operand         Right operand   Result type
                          type                 type

   **     exponentiation  any integer type     INTEGER         same as left
                          any floating point   INTEGER         same as left
                          type

Exponentiation with a positive exponent is equivalent to repeated multiplication of the left operand by itself, as indicated by the exponent and from left to right. For an operand of a floating point type, the exponent can be negative, in which case the value is the reciprocal of the value with the positive exponent. Exponentiation by a zero exponent delivers the value one. Exponentiation of a value of a floating point type is approximate (see 4.5.7). Exponentiation of an integer raises the exception CONSTRAINT_ERROR for a negative exponent.

References: array type, boolean type, bound of an array, component of an array, constraint_error exception, dimensionality, floating point type, index, integer type, multiplication operation, predefined operator, raising of exceptions.

Style Guide references: 5.5.3 Parenthetical Expressions

4.5.7. Accuracy of Operations with Real Operands

[PREVIOUS][UP]

A real subtype specifies a set of model numbers. Both the accuracy required from any basic or predefined operation giving a real result, and the result of any predefined relation between real operands are defined in terms of these model numbers.

A model interval of a subtype is any interval whose bounds are model numbers of the subtype. The model interval associated with a value that belongs to a real subtype is the smallest model interval (of the subtype) that includes the value. (The model interval associated with a model number of a subtype consists of that number only.)

For any basic operation or predefined operator that yields a result of a real subtype, the required bounds on the result are given by a model interval defined as follows:

The result model interval is undefined if the absolute value of one of the above mathematical results exceeds the largest safe number of the result type. Whenever the result model interval is undefined, it is highly desirable that the exception NUMERIC_ERROR be raised if the implementation cannot produce an actual result that is in the range of safe numbers. This is, however, not required by the language rules, in recognition of the fact that certain target machines do not permit easy detection of overflow situations. The value of the attribute MACHINE_OVERFLOWS indicates whether the target machine raises the exception NUMERIC_ERROR in overflow situations (see 13.7.3).

The safe numbers of a real type are defined (see 3.5.6) as a superset of the model numbers, for which error bounds follow the same rules as for model numbers. Any definition given in this section in terms of model intervals can therefore be extended to safe intervals of safe numbers. A consequence of this extension is that an implementation is not allowed to raise the exception NUMERIC_ERROR when the result interval is a safe interval.

For the result of exponentiation, the model interval defining the bounds on the result is obtained by applying the above rules to the sequence of multiplications defined by the exponent, and to the final division in the case of a negative exponent.

For the result of a relation between two real operands, consider for each operand the model interval (of the operand subtype) defined for the operand; the result can be any value obtained by applying the mathematical comparison to values arbitrarily chosen in the corresponding operand model intervals. If either or both of the operand model intervals is undefined (and if neither of the operand evaluations raises an exception) then the result of the comparison is allowed to be any possible value (that is, either TRUE or FALSE).

The result of a membership test is defined in terms of comparisons of the operand value with the lower and upper bounds of the given range or type mark (the usual rules apply to these comparisons).

Note:

For a floating point type the numbers 15.0, 3.0, and 5.0 are always model numbers. Hence X/Y where X equals 15.0 and Y equals 3.0 yields exactly 5.0 according to the above rules. In the general case, division does not yield model numbers and in consequence one cannot assume that (1.0/X)*X = 1.0.

References: attribute, basic operation, bound of a range, error bound, exponentiation operation, false boolean value, floating point type, machine_overflows attribute, membership test, model number, multiplication operation, numeric_error exception, predefined operation, raising of exceptions, range, real type, relation, relational operator, and 4.5, safe number, subtype, true boolean value, type conversion, type mark, universal expression, and 4.

Style Guide references: 5.5.6 Accuracy of Operations With Real Operands, 7.2.2 Ada Model, 7.2.3 Analysis, 7.2.4 Accuracy Constraints, 7.2.5 Comments, 7.2.7 Subexpression Evaluation

[INDEX][CONTENTS]


[Ada Information Clearinghouse]

Address any questions or comments to adainfo@sw-eng.falls-church.va.us.