Rationale for Ada 2012
6.2 Position of pragmas and labels
It is surprising that basic stuff such as where one
can place a pragma should be the subject of discussion thirty years after
Ada became an ANSI standard.
However, there is a real problem in this area which
one could imagine might have led to headlines in the Wall Street Journal
and Financial Times such as
Collapse
of NY Stock Market because of Safety Fears in Avionic Applications after
Discovery that Ada is Illegal
Indeed, it seems that
the package
Ada in Ada 2005 might be illegal.
This surprising conclusion was triggered by the consideration of
task type TT is
pragma Priority(12);
end TT;
The rules in Ada 83, Ada 95 and Ada 2005 concerning
the position of pragmas say
Pragmas are only allowed
at the following places in a program:
After a semicolon delimiter, but not within a formal
part or discriminant part.
At any place where the syntax rules allow a construct
defined by a syntactic category whose name ends with "declaration",
"statement", "clause",
or "alternative"; or one of the
syntactic categories variant or exception_handler;
but not in place of such a construct. Also at any place where a compilation_unit
would be allowed.
Now the syntax for
task_definition in Ada 2005 is
task_definition ::=
{task_item}
[private
{task_item}]
end [task_identifier]}
There are at least two problems. The key one here
is that the list of categories in the rule does not include "item".
The other concerns the words "not in place of". It seems that
the intent was that if at least one instance of the construct is required
(as in a sequence of statements) then the pragma cannot be given in place
of a single statement. So it looks as if the task type TT
is not legal.
It has probably been permitted because task_item
itself splits down into aspect_clause or entry_declaration and they seem
to be allowed. But if none is present then we cannot tell which category
is permitted!
Note rather scarily
that the package Ada is given as
package Ada is
pragma Pure(Ada);
end Ada;
and the same problem applies.
The entities in a package specification are of the
category basic_declarative_item and again although it splits down into
things ending _clause or _declaration we don't know which.
The fear concerning package Ada
made one member of the ARG concerned that the sky might be falling in.
Of course, we don't ever have to submit a package Ada
in our file (on punched cards, paper tape or whatever media we are using).
The package Ada is just in the mind of the
compiler so that it behaves as if she were declared. The same applies
to Standard. They are sort of synthesized
and not actually declared.
Anyway, the upshot is that in Ada 2012, the description
of the placement of pragmas is corrected by adding "item" to
the list and clarifying the meaning of not in place of.
A further discussion
considered sequences of statements. In a structure such as an if statement
the syntax is
if_statement ::=
if condition then
sequence_of_statements
...
where
sequence_of_statements ::= statement {statement}
The important point
is that a sequence_of_statements must have at least one statement. Moreover,
the rules for placing pragmas in Ada 2005 do not allow a pragma in place
of a construct so we cannot write
if B then
pragma Assert( ... ); -- illegal in Ada 2005
else ...
but have to include
at least one statement (such as a null statement) by writing perhaps
if B then
pragma Assert( ... ); null;
else ...
or
if B then
null; pragma Assert( ... );
else ...
On reflection this
seemed irritating so the rules for the placement of pragmas are further
amended to include another bullet
In place of a statement
in a sequence_of_statements
A useful note on a language definition principle
is added to the AARM which is that if all pragmas are treated as unrecognized
then a program should remain legal.
Incidentally, there
are other places in the language where at least one item is required
such as in a component list. Again if we don't want any components we
have to write a null component as in
type Nothing is
record
null;
end record;
One might have thought
that we could similarly now allow one to write
type T is
record
pragma Page;
end record;
Indeed, it might have
been thought that we could simply say that in general a pragma can be
given "in place of" an entity. But this doesn't work in some
cases. For example, an asynchronous select statement can take the form
of a series of statements in its triggering alternative thus
select
S1( ... );
S2( ... );
S3( ... );
then abort
...
end select;
Now the call of S1 is
the triggering statement and has a different status to S2
and S3. It would be very confusing to be able
to replace the call of S1 by a pragma. So
such generalization was dismissed as leading to trouble.
The final topic in
this vein concerns the position of labels. This was triggered by the
consideration of the problem of quitting one iteration of a loop if it
proves unsuccessful and then trying the next iteration. As described
in the Introduction (see
1.3.5) this can
be done by writing
for I in Some_Range loop
...
if not OK then goto End_Of_Loop; end if;
... -- lots of other code
<<End_Of_Loop> null; -- try another iteration
end loop;
Of course, maybe we
should avoid the goto and write
for I in Some_Range loop
...
if OK then
... -- lots of other code
end if;
-- try another iteration
end loop;
At first sight the latter structure looks nicer.
However, if the "lots of other code" encounters several situations
which mean that the iteration has to be abandoned then we quickly get
a deeply nested structure which is not easy to understand and becomes
heavily indented.
Much consideration was given to the introduction
of a continue statement but it was felt that this would obscure the existence
of the transfer of control. Although the goto may be deprecated as obscure,
the corresponding obvious label in its aggressive double angle brackets
is a strong clue to the existence of the transfer of control.
In the end it was decided that the only sensible
improvement was to remove the need for the null statement at the end
of the loop.
This is achieved by
changing the syntax for a sequence of statements to
sequence_of_statements ::= statement {statement} {label}
where (as before)
statement ::= {label} simple_statement
| {label} compound_statement
so that as well as
being permitted before a statement, a label can also follow a sequence
of statements. In addition, a rule is added to the effect that if one
or more labels end a sequence of statements then an implicit null statement
is inserted after the labels. This rule is necessary because the effect
of the goto statement is described in terms of going to the statement
after the label. So the loop example can now be written as
for I in Some_Range loop
...
if not OK then goto End_Of_Loop; end if;
... -- lots of other code
<<End_Of_Loop> -- try another iteration
end loop;
More generally we can
write
if B then
S1; S2; <<My_Label>>
end if;
as well as giving the
null explicitly thus
if B then
S1; S2; <<My_Label>> null;
end if;
but we still cannot
write
if B then
<<My_Label>> -- illegal
end if;
since a sequence of statements must still include
at least one statement. Of course, we could never jump to such a label
anyway since control cannot be transferred into a structure.
© 2011, 2012, 2013 John Barnes Informatics.
Sponsored in part by: