Rationale for Ada 2012

John Barnes
Contents   Index   References   Search   Previous   Next 

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

Contents   Index   References   Search   Previous   Next 
© 2011, 2012, 2013 John Barnes Informatics.
Sponsored in part by:
The Ada Resource Association:

    ARA
  AdaCore:


    AdaCore
and   Ada-Europe:

Ada-Europe