Annotated Ada Reference ManualLegal Information
Contents   Index   References   Search   Previous   Next 

3.2.4 Subtype Predicates

1/3
{AI05-0153-3} {AI05-0269-1} {AI05-0299-1} The language-defined predicate aspects Static_Predicate and Dynamic_Predicate may be used to define properties of subtypes. A predicate specification is an aspect_specification for one of the two predicate aspects. General rules for aspects and aspect_specifications are found in Clause Section 13 (13.1 and 13.1.1 respectively). 
1.a/3
Aspect Description for Static_Predicate: Condition that must hold true for objects of a given subtype; the subtype may be static.
1.b/3
Aspect Description for Dynamic_Predicate: Condition that must hold true for objects of a given subtype; the subtype is not static.

Name Resolution Rules

2/3
{AI05-0153-3} The expected type for a predicate aspect expression is any boolean type.

Static Semantics

3/3
{AI05-0153-3} A predicate specification may be given on a type_declaration or a subtype_declaration, and applies to the declared subtype. In addition, predicate specifications apply to certain other subtypes: 
4/3
For a (first) subtype defined by a derived type declaration, the predicates of the parent subtype and the progenitor subtypes apply.
5/3
For a subtype created by a subtype_indication, the predicate of the subtype denoted by the subtype_mark applies. 
6/3
{AI05-0153-3} The predicate of a subtype consists of all predicate specifications that apply, and-ed together; if no predicate specifications apply, the predicate is True [(in particular, the predicate of a base subtype is True)].
7/3
{AI05-0290-1} Predicate checks are defined to be enabled or disabled for a given subtype as follows:
8/3
If a subtype is declared by a type_declaration or subtype_declaration that includes a predicate specification, then: 
9/3
if performing checks is required by the Static_Predicate assertion policy (see 11.4.2) and the declaration includes a Static_Predicate specification, then predicate checks are enabled for the subtype;
10/3
if performing checks is required by the Dynamic_Predicate assertion policy (see 11.4.2) and the declaration includes a Dynamic_Predicate specification, then predicate checks are enabled for the subtype;
11/3
otherwise, predicate checks are disabled for the subtype[, regardless of whether predicate checking is enabled for any other subtypes mentioned in the declaration];
12/3
If a subtype is defined by a derived type declaration that does not include a predicate specification, then predicate checks are enabled for the subtype if and only if predicate checks are enabled for at least one of the parent subtype and the progenitor subtypes;
13/3
If a subtype is created by a subtype_indication other than in one of the previous cases, then predicate checks are enabled for the subtype if and only if predicate checks are enabled for the subtype denoted by the subtype_mark;
14/3
Otherwise, predicate checks are disabled for the given subtype.
14.a/3
Discussion: In this case, no predicate specifications can apply to the subtype and so it doesn't typically matter whether predicate checks are enabled. This rule does make a difference, however, when determining whether predicate checks are enabled for another type when this type is one of multiple progenitors. See the “derived type declaration” wording above.
14.b/3
Even when predicate checks are disabled, a predicate cam affect various Legality Rules, the results of membership tests, the items in a for loop, and the result of the Valid attribute. 

Legality Rules

15/3
 {AI05-0153-3} {AI05-0269-1} The expression of a Static_Predicate specification shall be predicate-static; that is, one of the following:
16/3
a static expression;
17/3
a membership test whose simple_expression is the current instance, and whose membership_choice_list meets the requirements for a static membership test (see 4.9);
18/3
a case_expression whose selecting_expression is the current instance, and whose dependent_expressions are static expressions;
19/3
a call to a predefined equality or ordering operator, where one operand is the current instance, and the other is a static expression;
20/3
{AI05-0262-1} a call to a predefined boolean logical operator, where each operand is predicate-static;
21/3
{AI05-0269-1} a short-circuit control form where both operands are predicate-static; or
22/3
a parenthesized predicate-static expression.
23/3
 {AI05-0262-1} A predicate shall not be specified for an incomplete subtype.
23.a/3
Reason: The expression of such a predicate could not depend on the properties of the value of the type (since it doesn't have any), so it is useless and we don't want to require the added complexity needed to support it. 
24/3
 {AI05-0287-1} If a predicate applies to a subtype, then that predicate shall not mention any other subtype to which the same predicate applies.
24.a/3
Reason: This is intended to prevent recursive predicates, which cause definitional problems for static predicates. Inside of the predicate, the subtype name refers to the current instance of the subtype, which is an object, so a direct use of the subtype name cannot be recursive. But other subtypes naming the same type might: 
24.b/3
   type Really_Ugly is private;
private
   subtype Ugly is Really_Ugly;
   type Really_Ugly is new Integer
      with Static_Predicate => Really_Ugly not in Ugly; -- Illegal!
25/3
 {AI05-0153-3} An index subtype, discrete_range of an index_constraint or slice, or a discrete_subtype_definition of a constrained_array_definition, entry_declaration, or entry_index_specification shall not denote a subtype to which predicate specifications apply.
26/3
 {AI05-0153-3} The prefix of an attribute_reference whose attribute_designator is First, Last, or Range shall not denote a scalar subtype to which predicate specifications apply.
26.a/3
Reason: {AI05-0297-1} This is to prevent confusion about whether the First value is the lowest value of the subtype (which does not depend on the predicate) or the lowest value of the subtype which meets the predicate. (For a dynamic predicate, determining this latter value is expensive as it would usually require a loop.) For a static subtype that has a static predicate, the First_Valid and Last_Valid attributes (see 3.5.5) can be used instead. 
27/3
 {AI05-0153-3} {AI05-0262-1} {AI05-0287-1} The discrete_subtype_definition of a loop_parameter_specification shall not denote a nonstatic subtype to which predicate specifications apply or any subtype to which Dynamic_Predicate specifications apply.
28/3
 {AI05-0153-3} {AI05-0262-1} The discrete_choice of a named_array_aggregate shall not denote a nonstatic subtype to which predicate specifications apply.
28.a/3
Reason: {AI05-0262-1} This rule prevents noncontiguous dynamically bounded array aggregates, which could be expensive to check for. (Array aggregates have rules to prevent problems with static subtypes.) We define this rule here so that the runtime generic body check applies. 
29/3
 {AI05-0262-1} In addition to the places where Legality Rules normally apply (see 12.3), these rules apply also in the private part of an instance of a generic unit.

Dynamic Semantics

30/3
 {AI05-0153-3} {AI05-0290-1} If predicate checks are enabled for a given subtype, then: 
31/3
[On every subtype conversion, the predicate of the target subtype is evaluated, and a check is performed that the predicate is True. This includes all parameter passing, except for certain parameters passed by reference, which are covered by the following rule: ] After normal completion and leaving of a subprogram, for each in out or out parameter that is passed by reference, the predicate of the subtype of the actual is evaluated, and a check is performed that the predicate is True. For an object created by an object_declaration with no explicit initialization expression, or by an uninitialized allocator, if any subcomponents have default_expressions, the predicate of the nominal subtype of the created object is evaluated, and a check is performed that the predicate is True. Assertions.Assertion_Error is raised if any of these checks fail.
31.a/3
Ramification: Predicates are not evaluated at the point of the (sub)type declaration. 
31.b/3
Implementation Note: Static_Predicate checks can be removed even in the presence of potentially invalid values, just as constraint checks can be removed. 
32/3
 {AI05-0262-1} A value satisfies a predicate if the predicate is True for that value.
33/3
 {AI05-0153-3} {AI05-0276-1} If any of the above Legality Rules is violated in an instance of a generic unit, Program_Error is raised at the point of the violation.
33.a/3
Discussion: This is the usual way around the contract model; this applies even in instance bodies. Note that errors in instance specifications will be detected at compile-time by the "re-check" of the specification, only errors in the body should raise Program_Error. 
NOTES
34/3
5  {AI05-0153-3} A predicate specification does not cause a subtype to be considered constrained.
35/3
6  {AI05-0153-3} A Static_Predicate, like a constraint, always remains True for all objects of the subtype, except in the case of uninitialized variables and other invalid values. A Dynamic_Predicate, on the other hand, is checked as specified above, but can become False at other times. For example, the predicate of a record subtype is not checked when a subcomponent is modified. 

Extensions to Ada 2005

35.a/3
{AI05-0153-3} {AI05-0262-1} {AI05-0276-1} {AI05-0290-1} Predicate aspects are new in Ada 2012. 

Contents   Index   References   Search   Previous   Next 
Ada-Europe Ada 2005 and 2012 Editions sponsored in part by Ada-Europe