Version 1.6 of ai05s/ai05-0030-2.txt

Unformatted version of ai05s/ai05-0030-2.txt version 1.6
Other versions for file ai05s/ai05-0030-2.txt

!standard 9.5(9)          08-04-21 AI05-0030-2/04
!standard 9.5.4(2)
!standard 9.5.4(3)
!standard 9.5.4(5)
!standard 9.5.4(6)
!standard 9.5.4(7)
!standard 9.5.4(12)
!class Binding Interpretation 06-10-13
!status Amendment 201Z 08-11-26
!status WG9 Approved 08-06-20
!status ARG Approved 6-0-2 08-02-09
!status work item 06-10-13
!status received 06-10-13
!priority Medium
!difficulty medium
!subject Requeue on synchronized interfaces
!summary
Requeue is permitted to a synchronized, task, or protected interface if it is known that the operation is an entry. A new pragma is provided to accomplish this.
!problem
The inability to requeue to a synchronized, task or protected interface is a serious drawback when trying to produce general-purpose real-time utilities. Its inclusion would further the integration of the OO and concurrency features of the language.
!proposal
The proposal is to allow requeue to procedures defined in synchronized, task, or protected interfaces provided that the pragma Implemented specifies that the procedure is implemented by an entry.
!wording
Add after 9.5(9)
Syntax
The form of a pragma Implemented is as follows
pragma Implemented(procedure_local_name, implementation_kind); implementation_kind ::= By_Entry | By_Protected_Procedure | By_Any
Legality Rules
The procedure_local_name of a pragma Implemented shall denote a primitive procedure of a synchronized tagged type.
AARM Ramification: The procedure_local_name can denote more than one such procedure if there are several overloaded routines. No functions can be denoted, even if one or more procedures are also denoted.
A pragma Implemented with implementation_kind By_Protected shall not be applied to a primitive procedure of a task interface.
A procedure for which the implementation_kind is specified as By_Entry shall be implemented by an entry. A procedure for which the implementation_kind is specified as By_Protected_Procedure shall be implemented by a protected procedure.
If a primitive procedure overrides an inherited operation to which a pragma Implemented applies then any pragma Implemented applied to the overriding operation shall have the same implementation_kind or the inherited implementation_kind shall be By_Any.
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.
Static Semantics
A pragma Implemented is said to apply to the procedure denoted by its procedure_local_name. If an overriding operation does not have a pragma Implemented then any pragma Implemented applying to the inherited operation applies to the overriding operation.
NOTE
18 The implementation_kind By_Protected_Procedure implies that the operation will not block.
Replace 9.5.4(2-3):
requeue_statement ::= requeue *procedure_or_entry_*name [with abort];
Name Resolution Rules
The procedure_or_entry_name of a requeue_statement shall resolve to denote a procedure or an entry (the requeue target) that either has no parameters, or that has a profile that is type conformant (see 6.3.1) with the profile of the innermost enclosing entry_body or accept_statement.
Replace 9.5.4(5):
If the requeue target has parameters, then its profile shall be subtype conformant with the profile of the innermost enclosing callable construct.
If the target is a procedure, the name shall denote a rename of an entry, or shall denote a prefixed view of a primitive subprogram of a synchronized interface, where the first parameter of the unprefixed view of the primitive subprogram shall be a controlling parameter, and a pragma Implemented with implementation_kind By_Entry shall apply to the primitive subprogram.
Modify 9.5.4(6) as follows:
"...entry_declaration {for the entry_body}."
Modify 9.5.4(7) as follows:
The execution of a requeue_statement proceeds by first evaluating the [entry_name]{procedure_or_entry_name} ...
Modify 9.5.4(12) as follows:
If the [new entry]{requeue target} named in the requeue_statement has parameters, then during the execution of an accept_statement or entry_body corresponding to a new entry ...
!discussion
A previous alternative of this AI (0030-1) regarding this problem permitted the requeue syntactically and then had to resolve what would happen if the target turned out to be implemented by a procedure and not by an entry. This introduced bounded errors and looked difficult to implement.
Accordingly, this version takes a more static view. We need to ensure that the requeue will always turn out to be on an entry and not on a procedure or protected procedure.
Ideally, this should be done by new syntax which introduces entry into the profile of the interface. For example
type Server is synchronized interface; entry Q(S: in out Server; X: Item);
However, this approach could not be classed as a binding interpretation but would have to be an Amendment.
Accordingly a pragma is proposed which can be used thus
type Server is synchronized interface; procedure Q(S: in out Server; X: Item); pragma Implemented(Q, By_Entry);
For completeness, the pragma can also take parameters, By_Protected_Procedure or By_Any. By_Protected_Procedure means that it has to be implemented by a protected procedure and By_Any means it can be implemented by a normal procedure, a protected procedure or by an entry (these might be useful documentation aids). In particular, if it is known that an operation is implemented by a protected procedure then it can be deduced that the operation will not block under normal circumstances (eg on a monoprocessor).
The pragma can also be applied to task and protected interfaces. In the former case By_Protected_Procedure is not permitted.
If an interface inherits an operation from another interface and the inherited operation is subject to a pragma Implemented then that property is inherited. It can be specified again but must not conflict. By_Any can be overridden by By_Entry or By_Protected_Procedure but in other cases the parameter must match. And of course a task interface cannot inherit operations to which By_Protected_Procedure applies.
For example if we have
type Server is synchronized interface; procedure Q(S: in out Server; X: Item); pragma Implemented(Q, By_Protected_Procedure);
then it is illegal to write
type T_Server is task interface and Server; -- illegal
Since it is statically determined we now permit a requeue on an entry renamed as a procedure.
The boilerplate for checking in the private part of a generic is necessary so that derivations from formal interfaces and from formal derived types do not violate these rules. For example:
generic type Sync is synchronized interface; package Gen is ... private type New_Sync is new Sync with ...; procedure Flub (Obj : in New_Sync; ...); pragma Implemented(Flub, By_Entry); -- OK. end Gen;
type Gag is synchonized interface; procedure Flub (Obj : in Gag; ...); pragma Implemented(Flub, By_Protected_Procedure);
package Inst is new Gen (Gag); -- Error:
In this case, procedure Flub in the instance has conflicting pragma Implemented that apply to it; this must be detected.
We don't need assume-the-worst rules for generic bodies because derivation from formal tagged types is illegal in bodies by 3.9.1(4/2).
When discussed at the IRTAW the need to requeue via interface procedures implemented by entries was strongly supported. However there was no wish to have requeue to a procedure so the proposal of this present AI covers the perceived need.
!example
See the paper 'Integrating OOP and Tasking - the missing requeue' by Wellings and Burns (IRTAW2007), previously circulated. Find it at http://www.ada-auth.org/ai-files/grab_bag/requeue.pdf.
!corrigendum 9.5(9)
Insert after the paragraph:
Any call on a protected procedure or entry of a target protected object is defined to be an update to the object, as is a requeue on such an entry.
the new paragraphs:
Syntax
The form of a pragma Implemented is as follows pragma Implemented(procedure_local_name, implementation_kind); implementation_kind ::= By_Entry | By_Protected_Procedure | By_Any
Legality Rules
The procedure_local_name of a pragma Implemented shall denote a primitive procedure of a synchronized tagged type.
A pragma Implemented with implementation_kind By_Protected shall not be applied to a primitive procedure of a task interface.
A procedure for which the implementation_kind is specified as By_Entry shall be implemented by an entry. A procedure for which the implementation_kind is specified as By_Protected_Procedure shall be implemented by a protected procedure.
If a primitive procedure overrides an inherited operation to which a pragma Implemented applies then any pragma Implemented applied to the overriding operation shall have the same implementation_kind or the inherited implementation_kind shall be By_Any.
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.
Static Semantics
A pragma Implemented is said to apply to the procedure denoted by its procedure_local_name. If an overriding operation does not have a pragma Implemented then any pragma Implemented applying to the inherited operation applies to the overriding operation.
NOTE 18 The implementation_kind By_Protected_Procedure implies that the operation will not block.
!corrigendum 9.5.4(2)
Replace the paragraph:
requeue_statement ::= requeue entry_name [with abort];
by:
requeue_statement ::= requeue procedure_or_entry_name [with abort];
!corrigendum 9.5.4(3)
Replace the paragraph:
The entry_name of a requeue_statement shall resolve to denote an entry (the target entry) that either has no parameters, or that has a profile that is type conformant (see 6.3.1) with the profile of the innermost enclosing entry_body or accept_statement.
by:
The procedure_or_entry_name of a requeue_statement shall resolve to denote a procedure or an entry (the requeue target) that either has no parameters, or that has a profile that is type conformant (see 6.3.1) with the profile of the innermost enclosing entry_body or accept_statement.
!corrigendum 9.5.4(5)
Replace the paragraph:
If the target entry has parameters, then its profile shall be subtype conformant with the profile of the innermost enclosing callable construct.
by:
If the requeue target has parameters, then its profile shall be subtype conformant with the profile of the innermost enclosing callable construct.
If the target is a procedure, the name shall denote a rename of an entry, or shall denote a prefixed view of a primitive subprogram of a synchronized interface, where the first parameter of the unprefixed view of the primitive subprogram shall be a controlling parameter, and a pragma Implemented with implementation_kind By_Entry shall apply to the primitive subprogram.
!corrigendum 9.5.4(6)
Replace the paragraph:
In a requeue_statement of an accept_statement of some task unit, either the target object shall be a part of a formal parameter of the accept_statement, or the accessibility level of the target object shall not be equal to or statically deeper than any enclosing accept_statement of the task unit. In a requeue_statement of an entry_body of some protected unit, either the target object shall be a part of a formal parameter of the entry_body, or the accessibility level of the target object shall not be statically deeper than that of the entry_declaration.
by:
In a requeue_statement of an accept_statement of some task unit, either the target object shall be a part of a formal parameter of the accept_statement, or the accessibility level of the target object shall not be equal to or statically deeper than any enclosing accept_statement of the task unit. In a requeue_statement of an entry_body of some protected unit, either the target object shall be a part of a formal parameter of the entry_body, or the accessibility level of the target object shall not be statically deeper than that of the entry_declaration for the entry_body.
!corrigendum 9.5.4(7)
Replace the paragraph:
The execution of a requeue_statement proceeds by first evaluating the entry_name, including the prefix identifying the target task or protected object and the expression identifying the entry within an entry family, if any. The entry_body or accept_statement enclosing the requeue_statement is then completed, finalized, and left (see 7.6.1).
by:
The execution of a requeue_statement proceeds by first evaluating the procedure_or_entry_name, including the prefix identifying the target task or protected object and the expression identifying the entry within an entry family, if any. The entry_body or accept_statement enclosing the requeue_statement is then completed, finalized, and left (see 7.6.1).
!corrigendum 9.5.4(12)
Replace the paragraph:
If the new entry named in the requeue_statement has formal parameters, then during the execution of the accept_statement or entry_body corresponding to the new entry, the formal parameters denote the same objects as did the corresponding formal parameters of the callable construct completed by the requeue. In any case, no parameters are specified in a requeue_statement; any parameter passing is implicit.
by:
If the requeue target named in the requeue_statement has formal parameters, then during the execution of the accept_statement or entry_body corresponding to the new entry, the formal parameters denote the same objects as did the corresponding formal parameters of the callable construct completed by the requeue. In any case, no parameters are specified in a requeue_statement; any parameter passing is implicit.
!ACATS test
Create ACATS tests to check that the above changes work. B-Tests are needed for the legality rules and C-Tests for actual dispatching requeuing.
!appendix

From: Randy Brukardt
Sent: Friday, January 4, 2008  6:42 PM

John writes:

> Attached is the AI on requeue. It has been reviewed by Tucker and Alan so
> has a fair chance of being reasonable.

The basic idea seems OK, but it seems to have some issues in the details.

(Oooo, and it is such fun to play editor with someone else's creation for a
change. :-) It's always disappointing to have people pick apart your carefully
crafted text...even if they're right.)

You have:

>                        Legality Rules
>
> The *procedure_*local_name of a pragma Implemented shall denote a 
> dispatching operation of a synchronized interface. 
> The dispatching operation shall not be a function.

It could denote more than one such operation if there is overloading. Is that
intended/allowed? Do we need to say something about it? I'd think that there
should be at least an AARM note or some discussion on this topic (it is one of
the main reasons that syntax is *so* much better.)

>                        Static Semantics
>
> An operation for which the implementation_kind is specified as By_Entry 
> shall be implemented by an entry. An operation for which the 
> implementation_kind is specified as By_Protected_Procedure shall be 
> implemented by a protected procedure.
>
> If a dispatching operation overrides an inherited operation to which a 
> pragma Implemented applies then any pragma Implemented applied to the 
> overriding operation shall not conflict with regard to the 
> implementation_kind. Both implementation_kinds shall be the same or the 
> inherited implementation_kind shall be By_Any. If an overriding operation 
> does not have a pragma Implemented then any pragma Implemented applying to 
> the inherited operation shall apply to the overriding operation.

Most of this seems to be Legality Rules, not Static Semantics. Surely, if you have
a rule that says that a Blah shall be a Glorp, that's a legality rule. It surely needs
an ACATS test to check that violations are detected.

Only the very last sentence seems to be a Static Semantics rule, so it probably
should be in a separate paragraph. And I'd keep "shall" out of it. This pragma
is fairly similar in semantics to No_Return, so I'd probably try to copy that
wording. (And, indeed, this is fairly similar to No_Return's wording.) I'm not
certain that what it means for a pragma to "apply" is clearly defined anywhere
other than in the inheritance case. We probably need a sentence like "The pragma
Implemented applies to the subprograms denoted by the procedure_local_name".

The first two sentences of the second paragraph say the same thing (the latter probably
being the formal definition. I wonder if they can be combined (dropping the part about
"shall not conflict" -- that's for your book!)

>                              NOTE
>
> 18 The implementation_kinds By_Protected_Procedure and By_Any may be used 
>    as documentation aids.

Does this note tell the reader something interesting? It does not seem so to me
(we don't need a note in the RM to help justify the AI, nor to say something
obvious). It would make more sense for the note to say something similar to what
the discussion does: "In particular, if it is known that an operation is implemented
by a protected procedure then it can be deduced that the operation will not block
under normal circumstances (eg on a monoprocessor)." ...which seems like a useful
statement.

In the change to 9.5.4(2-5):

> ...and the pragma Implement with implementation_kind By_Entry 
> shall apply to the primitive subprogram.

I think this ought to be "pragma Implemented"; there is no pragma Implement.

I don't see any change to 9.5.4(4); probably it shouldn't be in the changed text
because it is a real time-waster to look at it over and over trying to see what
is different. (That is, the changes to 9.5.4(2-3) and 9.5.4(5) should be given
separately.)

Annex L is automatically created, and we rarely talk about it in AIs (the notion
that it and Annex K get updated is just assumed). So I'd just drop that sentence.

The first paragraph of the discussion has "bounded errora".

Baird-type question: You say in the discussion that "...then it is illegal to write

   type T_Server is task interface and Server;     -- illegal

Since it is statically determined we now permit a requeue on an entry 
renamed as a procedure."

This seems like it could be a contract issue for formal interfaces and formal
derived types. It seems like we would want assume-the-best + recheck rules for
occurrences in a generic specification. (Luckily, deriving from these things is
illegal in a body.) At a very minimum, we need the boilerplate line about the
legality rules being checked in the private part. (Indeed, that needs to be
considered for all of these new legality rules.)

One example would be something like:

    generic
        type Sync is synchronized interface;
    package Gen is
        ...
    private
        type New_Sync is new Sync with ...;
        procedure Flub (Obj : in New_Sync; ...);
        pragma Implemented(Flub, By_Entry); -- OK (I hope so).
    end Gen;

    type Garg is synchonized interface;
    procedure Flub (Obj : in Garg; ...);
    pragma Implemented(Flub, By_Protected_Procedure);

    package Inst is new Gen (Garg); -- !!

There better be an error here (because of the Implemented mismatch in the
derived type), and there won't be without the boilerplate.

There is also the other way to consider - is there a problem requeuing onto
an inherited operation of a generic formal derived type? (I don't think so.) 

> Javier Miranda has indicated that he is prepared
> to develop a prototype implementation to evaluate the impact of 
> such a proposal.)

There is at least a stray ")" here. But I wonder if this is true.
This seems to have been copied from the original AI, and it was talking
only about the requeue itself (and the impact on the runtime system). Are
we sure that anyone is planning to evaluate the impact of the pragmas (which
seem to be as much work to implement as the actual requeue, and are in a very
different part of the compiler)? If not, this should say something different
to restrict it to what the actual promise was.

Finally, the !appendix is copied from the original alternative. It should
be empty (other than this note!) - mail only appears once.

****************************************************************


Questions? Ask the ACAA Technical Agent