!topic LSN on Task Parameterization in Ada 9X !key LSN-1044 on Task Parameterization in Ada 9X !reference MS-3.6.1;4.6 !from Bob Duff $Date: 92/10/10 11:40:11 $ $Revision: 1.2 $ !discussion This Language Study Note discusses the issue of parameterizing tasks in Ada 9X. We consider three alternatives: Alternative 1: Task types should not have parameters. Alternative 2: Special 'Index Attribute. Alternative 3: Use the task id. Alternative 4: Task Discriminants. ALTERNATIVE 1: TASK TYPES SHOULD NOT HAVE PARAMETERS. In this alternative, there is no specific feature for parameterizing task types. Advantages: Tasks did not have parameters in Ada 83, so we're used to it. There is a workaround: one can pass parameters to a task via an extra initialization entry. Disadvantages: The extra initialization entry is much less efficient than the other alternatives discussed below. One must remember to call the extra initialization entry. The extra initialization entry is inconvenient, because the parameters cannot be passed at the point of the task object declaration. (Initialization at the point of declaration is an important feature of most of the classes of Ada types.) In the case of information that appears in the task declaration, the extra initialization entry is not even possible. This applies to entry family size, priority, and interrupt addresses. Priority, in particular, is important. It is useful to have several tasks that are identical except for priority, and it is important to get the priority set early. This alternative is less uniform, since it becomes harder to remember which types can have discriminants, and which cannot. Arbitrary restrictions frustrate users. ALTERNATIVE 2: SPECIAL 'INDEX ATTRIBUTE. In this alternative, there is a new attribute of a task. If the task is inside an array, the attribute returns its index. Advantages: Special-purpose gizmo may have less implementation impact. Disadvantages: Special-purpose gizmo may have more implementation impact. One needs to define the semantics when the task is NOT in an array. One needs to define when the attribute is legal. Must the compiler know that the task is in an array at compile time? The array object will generally be declared after the task body; by what mechanism can the compiler know? For example, are there extra restrictions on where the array object can be declared? What happens if an array component that is a task is passed as a parameter? Only certain applications naturally map to arrays of tasks. In many applications, requiring each task to be inside an array in order to pass information to it would be a burden on the programmer. The programmer cannot pass in the information needed in a straightforward manner. Instead, the only information allowed is a discrete value, which must then be used to look up the "real" information in a table. The most natural way to do this (which is not very natural), is to make an array of records. Each record would contain a task, plus the parameters of that task. The task body would then reach up into this array to get the parameters. But is this even allowed? Or does the special attribute only work for arrays of tasks? If arrays of records containing tasks work, then what if the record contains two tasks? Tasks that depend on variant parts? What special rules exist? If, on the other hand, the feature is restricted to arrays of tasks, then the parameters must be placed in a parallel array. But parallel arrays were recognized as being generally inferior to arrays of records some decades ago. Forcing the programmer into using parallel arrays where they are not natural would be seen as a step backwards. What if there are two or more arrays of the same task type? In that case, the array index is not a unique identifier. Is the attribute allowed in a task_declaration? Note that this is before any array object declaration, so the semantics of allowing it are questionable. However, if it is not allowed, then it cannot be used to parameterize information, such as priority, that appears in a task_spec. Non-uniformity of discriminant rules. ALTERNATIVE 3: USE THE TASK ID. The concensus is that there should be some sort of task identifier. (Although there has been some disagreement over the mechanism used -- TASK_CLASS or TASK_ID or whatever, pretty much everybody agrees that there should be SOME way to identify tasks.) In this alternative, we use the task id to identify the task, instead of having a special array-index attribute. Advantages: The only possible implementation impact is the non-uniformity of discriminant rules. There is no *additional* implementation impact due to task ids, since we already agree that they are needed for other reasons. The semantic issues that arise for Alternative 2 do not arise for Alternative 3. The task id is truly unique throughout the partition. Can be used in task_declarations without semantic difficulty. Disadvantages: There is still no natural way to pass parameters. Whatever the task id is, one needs to do a table lookup in order to get the real parameters. In this alternative, the table lookup is even worse than in Alternative 2 -- instead of simply indexing into an array, some more complicated data structure is necessary. This complicates the programmer's job, and makes the program less efficient (although probably still more efficient than an extra entry call). Non-uniformity of discriminant rules. ALTERNATIVE 4: TASK DISCRIMINANTS. In this alternative, we recognize that in Ada 9X, discriminants are a general mechanism for parameterizing types. In order to pass information to a task, one passes 'ACCESS of it to an access discriminant. If the data happens to be discrete, a discrete discriminant can be used instead. Advantages: Parameter passing is natural. The discriminant can be an access value pointing at any type, such as a record representing a job descriptor. There is no need for complicated or inefficient table lookups. (Note: We do not propose to allow discriminants to be composite, because of the pass-by-copy vs. pass-by-reference issues that rear their ugly heads.) Uniformity. Discriminants make sense for any composite type. In Ada 9X, we allow them for any composite type except array types. The array-type restriction is for ease of implementation -- it does not simplify the language nor make it easier to use. Adding another restriction for task types would decrease uniformity further. Discriminants are allowed for protected types; disallowing them for tasks would make tasks a second-class citizen. Some people think this rule is easier to implement, due to the uniformity. (This is the opinion of the MRT.) The implementation difficulties that arise for arrays do not come up for tasks. Efficiency. Discriminants are much more efficient than the extra initialization entry call required by Alternative 1, and are substantially more efficient than the table lookup of Alternative 3. (They are only a little bit more efficient than the table lookup of Alternative 2.) One cannot forget to initialize the task. The parameters are passed in at the point of the task object declaration, which is the most convenient place. Can be used in task_declarations. Disadvantages: The initialization entry provides a workaround in some cases. People are not yet used to the idea that discriminants are a general purpose mechanism for parameterization, since they were so heavily restricted in Ada 83.