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

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

!standard 9.5.4(3)          08-01-07 AI05-0030-2/02
!class Binding Interpretation 06-10-13
!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 an appropriate pragma is provided.
!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 dispatching operation of a synchronized interface. The dispatching operation shall not be a function.
AARM Ramification: The procedure_local_name can denote more than one such operation if there are several overloaded routines. None of the operations can be a non-dispatching operation or a function.
A pragma Implemented with implementation_kind By_Protected shall not be applied to a dispatching operation of a task interface.
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 be the same 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 declares that the operation will not block.
Change 9.5.4(2-3) to
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 target procedure or entry). In the case of an entry, the entry shall have a profile that has no parameters, or that is type conformant (see 6.3.1) with the profile of the innermost enclosing entry_body or accept_statement. In the case of a procedure, the name shall denote a rename of an entry whose profile satisfies the above requirement, or shall denote a prefixed view of a primitive subprogram of a synchronized interface where the profile of the prefixed view satisfies the above requirement, the first parameter of the unprefixed view of the primitive subprogram shall be a controlling parameter, and the pragma Implemented with implementation_kind By_Entry shall apply to the primitive subprogram.
Change 9.5.4(5) to
If the target procedure (view) or entry has parameters, then its profile shall be subtype conformant with the profile of the innermost enclosing callable construct.
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] {target procedure or }entry 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 version 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 syntactic 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
!ACATS test
Create an ACATS test to check that the above changes work.
!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