Skip to main content

4.4 Expressions


This Reference Manual output has not been verified, and may contain omissions or errors. Report any problems on the tracking issue


An expression is a formula that defines the computation or retrieval of a value. In this Reference Manual, the term “expression” refers to a construct of the syntactic category expression or of any of the following categories: choice_expression, choice_relation, relation, simple_expression, term, factor, primary, conditional_expression, quantified_expression.



expression ::=
relation {and relation} | relation {and then relation}
| relation {or relation} | relation {or else relation}
| relation {xor relation}


choice_expression ::=
choice_relation {and choice_relation}
| choice_relation {or choice_relation}
| choice_relation {xor choice_relation}
| choice_relation {and then choice_relation}
| choice_relation {or else choice_relation}


choice_relation ::=
simple_expression [relational_operator simple_expression]


relation ::=
simple_expression [relational_operator simple_expression]
| tested_simple_expression [not] in membership_choice_list
| raise_expression


membership_choice_list ::= membership_choice {'|' membership_choice}


membership_choice ::= choice_simple_expression | range | subtype_mark


simple_expression ::=
[unary_adding_operator] term {binary_adding_operator term}

term ::= factor{multiplying_operatorfactor}

factor ::= primary [** primary] | abs primary | not primary


primary ::=
numeric_literal | null | string_literal | aggregate
| name | allocator | (expression)
| (conditional_expression) | (quantified_expression)
| (declare_expression)

Name Resolution Rules


A name used as a primary shall resolve to denote an object or a value.


This replaces RM83-4.4(3). We don't need to mention named numbers explicitly, because the name of a named number denotes a value. We don't need to mention attributes explicitly, because attributes now denote (rather than yield) values in general. Also, the new wording allows attributes that denote objects, which should always have been allowed (in case the implementation chose to have such a thing).


It might seem odd that this is an overload resolution rule, but it is relevant during overload resolution. For example, it helps ensure that a primary that consists of only the identifier of a parameterless function is interpreted as a function_call rather than directly as a direct_name.

Static Semantics


Each expression has a type; it specifies the computation or retrieval of a value of that type.


A primary that is an expression surrounded by ( and ) is known as a parenthesized expression.


Every name or expression consists of one or more operative constituent names or expressions, only one of which is evaluated as part of evaluating the name or expression (the evaluated operative constituent). The operative constituents are determined as follows, according to the form of the expression (or name):

9.3/5 9.7/5

In certain contexts, we specify that an operative constituent shall (or shall not) be newly constructed. This means the operative constituent shall (or shall not) be an aggregate or a function_call; in either case, a raise_expression is permitted.


To be honest: If an if_expression does not have an else clause, "True" is an operative constituent of the expression and it can be the evaluated operative constituent.

Dynamic Semantics


The value of a primary that is a name denoting an object is the value of the object.


An expression of a numeric universal type is evaluated as if it has type root_integer (for universal_integer) or root_real (otherwise) unless the context identifies a specific type (in which case that type is used).


This has no effect for a static expression; its value may be arbitrarily small or large since no specific type is expected for any expression for which this rule specifies one of the root types. The only effect of this rule is to allow Constraint_Error to be raised if the value is outside of the base range of root_integer or root_real when the expression is not static.


This rule means that implementations don't have to support unlimited range math at run time for universal expressions. Note that universal expressions for which the context doesn't specify a specific type are quite rare; attribute prefixes and results are the only known cases. (For operators, 8.6 already specifies that the operator of a root type be used, which provides a specific type.)

Implementation Permissions


For the evaluation of a primary that is a name denoting an object of an unconstrained numeric subtype, if the value of the object is outside the base range of its type, the implementation may either raise Constraint_Error or return the value of the object.


This means that if extra-range intermediates are used to hold the value of an object of an unconstrained numeric subtype, a Constraint_Error can be raised on a read of the object, rather than only on an assignment to it. Similarly, it means that computing the value of an object of such a subtype can be deferred until the first read of the object (presuming no side effects other than failing an Overflow_Check are possible). This permission is over and above that provided by 11.6, since this allows the Constraint_Error to move to a different handler.


This permission is intended to allow extra-range registers to be used efficiently to hold parameters and local variables, even if they might need to be transferred into smaller registers for performing certain predefined operations.


There is no need to mention other kinds of primarys, since any Constraint_Error to be raised can be “charged” to the evaluation of the particular kind of primary.



Examples of primaries:


4.0 -- real literal Pi -- named number (1 .. 10 => 0) -- array aggregate Sum -- variable Integer'Last -- attribute Sine(X) -- function call Color'(Blue) -- qualified expression Real(M*N) -- conversion (Line_Count + 10) -- parenthesized expression


Examples of expressions:


Volume -- primary not Destroyed -- factor 2*Line_Count -- term -4.0 -- simple expression -4.0 + A -- simple expression B**2 - 4.0*A*C -- simple expression R*Sin(θ)*Cos(φ) -- simple expression Password(1 .. 3) = "Bwv" -- relation Count in Small_Int -- relation Count not in Small_Int -- relation Index = 0 or Item_Hit -- expression (Cold and Sunny) or Warm -- expression (parentheses are required) A**(B**C) -- expression (parentheses are required)

Extensions to Ada 83


In Ada 83, out parameters and their nondiscriminant subcomponents are not allowed as primaries. These restrictions are eliminated in Ada 95.


In various contexts throughout the language where Ada 83 syntax rules had simple_expression, the corresponding Ada 95 syntax rule has expression instead. This reflects the inclusion of modular integer types, which makes the logical operators "and", "or", and "xor" more useful in expressions of an integer type. Requiring parentheses to use these operators in such contexts seemed unnecessary and potentially confusing. Note that the bounds of a range still have to be specified by simple_expressions, since otherwise expressions involving membership tests might be ambiguous. Essentially, the operation ".." is of higher precedence than the logical operators, and hence uses of logical operators still have to be parenthesized when used in a bound of a range.

Wording Changes from Ada 2005


Moved qualified_expression from primary to name (see 4.1). This allows the use of qualified_expressions in more places.


Expanded membership test syntax (see 4.5.2).

Inconsistencies With Ada 2012


Corrigendum: Revised membership syntax to eliminate ambiguities. In some cases, previously ambiguous membership expressions will now have an unambiguous meaning. If an Ada 2012 implementation chose the "wrong" meaning, the expression could silently change meaning. Virtually all such expressions will become illegal because of type mismatches (and thus be incompatible, not inconsistent). However, if the choices are all of a Boolean type, resolution might succeed. For instance, A in B | C and D now always means (A in B | C) and D, but the original Ada 2012 syntax would have allowed it to mean A in B | (C and D). If a compiler allowed the expression and interpreted it as the latter, the meaning of the expression would silently change. We expect this to be extremely rare as membership operations on Boolean types are unlikely (and this can happen only in code written for Ada 2012).

Incompatibilities With Ada 2012


Corrigendum: The revised membership syntax will require parentheses in membership_choice_lists in some cases where the Ada 2012 grammar did not require them. For instance, A in B in C | D is now illegal. However, such expressions can be interpreted in multiple ways (either A in (B in C) | D or A in (B in C | D) for this example), so using such expressions is likely to be dangerous (another compiler might interpret the expression differently). In addition, all such expressions occur only in Ada 2012 syntax; so they should be rare.

Wording Changes from Ada 2012


Added wording so that universal expressions evaluated at run time can raise Constraint_Error if the value is outside of the range of root_integer or root_real. We don't document this as an inconsistency because the rule requires no implementation to change (as Constraint_Error is not required); it just allows implementations that already raise Constraint_Error (which is all of them surveyed) to be considered correct.


Added declare_expression to primary. It shares the rules about parentheses with conditional_expressions.


Added the definitions of “operative constituent” and “newly constructed” to centralize definitions that are needed for various rules and definitions across the Reference Manual. In particular, operative constituent is often used when we want the semantics or legality to be unchanged by the presence of parens, qualification, or view conversions. Examples are found in 4.3.2, 6.2, and 7.5.