5.4 Case Statements
[A
case_statement
selects for execution one of a number of alternative
sequences_of_statements;
the chosen alternative is defined by the value of an expression.]
Syntax
Name Resolution Rules
{expected type (case
expression) [partial]} The
expression
is expected to be of any discrete type.
{expected
type (case_statement_alternative discrete_choice) [partial]}
The expected type for each
discrete_choice
is the type of the
expression.
Legality Rules
The possible values of the
expression
shall be covered as follows:
Ramification: Although not official
names
of objects, a value conversion still has a defined nominal subtype, namely
its target subtype. See
4.6.
Reason: This is because the base range
is implementation defined for root_integer and universal_integer,
and not known statically in the case of a formal scalar type.
Otherwise, each value of the base range of the
type of the
expression
shall be covered [(either explicitly or by
others)].
Ramification: The goal of these coverage
rules is that any possible value of the
expression
of a
case_statement
should be covered by exactly one
discrete_choice
of the
case_statement,
and that this should be checked at compile time. The goal is achieved
in most cases, but there are two minor loopholes:
If the expression reads an object with an
invalid representation (e.g. an uninitialized object), then the value
can be outside the covered range. This can happen for static constrained
subtypes, as well as nonstatic or unconstrained subtypes. It cannot,
however, happen if the
case_statement
has the
discrete_choice
others, because
others covers all values, even those outside
the subtype.
{
AI95-00114-01}
If the compiler chooses to represent the value of an expression of an
unconstrained subtype in a way that includes values outside the bounds
of the subtype, then those values can be outside the covered range. For
example, if X: Integer := Integer'Last;, and the case
expression
is X+1, then the implementation might choose to produce the correct value,
which is outside the bounds of Integer. (It might raise Constraint_Error
instead.) This case can only happen for non-generic subtypes that are
either unconstrained or nonstatic (or both). It can only happen if there
is no
others discrete_choice.
In the uninitialized variable case, the value
might be anything; hence, any alternative can be chosen, or Constraint_Error
can be raised. (We intend to prevent, however, jumping to random memory
locations and the like.) In the out-of-range case, the behavior is more
sensible: if there is an
others, then the implementation may choose
to raise Constraint_Error on the evaluation of the
expression
(as usual), or it may choose to correctly evaluate the
expression
and therefore choose the
others alternative. Otherwise (no
others),
Constraint_Error is raised either way — on the
expression
evaluation, or for the
case_statement
itself.
For an enumeration type with a discontiguous
set of internal codes (see
13.4), the only
way to get values in between the proper values is via an object with
an invalid representation; there is no “out-of-range” situation
that can produce them.
Dynamic Semantics
{Overflow_Check
[partial]} {check,
language-defined (Overflow_Check)} {Constraint_Error
(raised by failure of run-time check)} Otherwise
(the value is not covered by any
discrete_choice_list,
perhaps due to being outside the base range), Constraint_Error is raised.
Ramification: In this case, the value
is outside the base range of its type, or is an invalid representation.
4 The execution of a
case_statement
chooses one and only one alternative. Qualification of the expression
of a
case_statement
by a static subtype can often be used to limit the number of choices
that need be given explicitly.
Examples
Examples of case
statements:
case Sensor is
when Elevation => Record_Elevation(Sensor_Value);
when Azimuth => Record_Azimuth (Sensor_Value);
when Distance => Record_Distance (Sensor_Value);
when others => null;
end case;
case Today is
when Mon => Compute_Initial_Balance;
when Fri => Compute_Closing_Balance;
when Tue .. Thu => Generate_Report(Today);
when Sat .. Sun => null;
end case;
case Bin_Number(Count) is
when 1 => Update_Bin(1);
when 2 => Update_Bin(2);
when 3 | 4 =>
Empty_Bin(1);
Empty_Bin(2);
when others => raise Error;
end case;
Incompatibilities With Ada 83
In addition, the rule about which choices must
be covered is unchanged in Ada 95. Therefore, for a
case_statement
whose
expression
is a
function_call
or
type_conversion,
Ada 83 required covering all choices in the base range, while Ada 95
only requires covering choices in the bounds of the subtype. If the
case_statement
does not include an
others discrete_choice,
then a legal Ada 83
case_statement
will be illegal in Ada 95 if the bounds of the subtype are different
than the bounds of the base type.
Extensions to Ada 83
{
extensions to Ada 83}
In
Ada 83, the
expression
in a
case_statement
is not allowed to be of a generic formal type. This restriction is removed
in Ada 95; an
others discrete_choice
is required instead.
In Ada 95, a function call is the name of an
object; this was not true in Ada 83 (see
4.1,
“
Names”). This change makes the
following
case_statement
legal:
subtype S is Integer range 1..2;
function F return S;
case F is
when 1 => ...;
when 2 => ...;
-- No others needed.
end case;
Note that the result subtype given in a function
renaming_declaration
is ignored; for a
case_statement
whose expression calls a such a function, the full coverage rules are
checked using the result subtype of the original function. Note that
predefined operators such as "+" have an unconstrained result
subtype (see
4.5.1). Note that generic formal
functions do not have static result subtypes. Note that the result subtype
of an inherited subprogram need not correspond to any namable subtype;
there is still a perfectly good result subtype, though.
Wording Changes from Ada 83
Ada 83 forgot to say what happens for “legally”
out-of-bounds values.
In the Name Resolution Rule for the case expression,
we no longer need RM83-5.4(3)'s “which must be determinable independently
of the context in which the expression occurs, but using the fact that
the expression must be of a discrete type,” because the
expression
is now a complete context. See
8.6, “
The
Context of Overload Resolution”.