!standard 9.5(17/3) 17-01-11 AI12-0064-2/06 !standard 9.5.1(8) !standard 9.5.1(9) !standard 9.5.1(10) !standard 9.5.1(11) !standard 9.5.1(12) !standard 9.5.1(13) !standard 9.5.1(14) !standard 9.5.1(15) !standard 9.5.1(16) !standard 9.5.1(18) !standard 9.5.1(22.1/2) !standard 3.10.2(33/3) !standard 4.6(24.21/4) !standard 4.9(8) !standard 13.1.1(17/4) !standard 13.13.2(37/1) !class Amendment 15-10-17 !status work item 15-12-18 !status received 15-10-17 !priority Medium !difficulty Medium !subject Nonblocking subprograms !summary Aspect and attribute Nonblocking are added. !problem During a protected action, it is a bounded error to invoke an operation that is potentially blocking. There is currently no mechanism (other than a comment) to specify that a given subprogram is intended to be safely callable during a protected action (i.e., that the subprogram will not invoke an operation that is potentially blocking). This seems like a useful part of a subprogram's "contract" that should be (optionally) specifiable at the point of a subprogram's declaration. !proposal [Summary of changes for June 2017 meeting: Applied the minor wording changes requested during meeting #56 (Pittsburgh). Added definition of nonblocking-static expressions, to reply to a comment from Steve Baird that a static expression cannot have different values in a generic unit and its associated instance. This means that the nonblocking attribute cannot be static in some cases for a generic unit, and we still want to allow such attribute references to be used to specify nonblocking aspects. The value used to specify a nonblocking aspect needs to be known at compile-time, so that it can be used to enforce Legality Rules. Thus we need this term to allow only static expressions and Nonblocking attributes, and combinations of them. Removed all notations that nonblocking attributes are static. I originally planned to leave them static other than when required to be nonstatic, but that proved hard to do (they can't be static when specified by an expression containing one or more Nonblocking attributes, even when the subprogram is non-generic). And it doesn't seem necessary for the rules; we just require them to be nonblocking-static when we need to require something. Tightened up the note 9.5.1(22.1/2) to say exactly what you have to do (specify the aspect to have the value True) rather than just "use" the aspect. Deleted a redundant rule about the Access attribute (it was given normatively in both 3.10.2 and 9.5). Finished the list of what needs to be done for non-container units. (Mostly adding "with Nonblocking => True"). Moved the rules about predefined operators into the aspect definition, since they sometimes contradict the other rules in that section (which isn't going to work.) ] [Editor's note: Individual rule changes scattered throughout the Standard follow this primary definition.] Add after 9.5(17/3): Static Semantics An expression is a nonblocking-static expression if it is one of the following: * a static expression; * a Nonblocking attribute reference; * a call to a predefined boolean logical operator and, or, xor, or not, where each operand is nonblocking-static; * a short-circuit control form where both operands are nonblocking-static; or * a parenthesized nonblocking-static expression. [Editor's note: This wording is intended to parallel the definition of predicate-static expression (from 3.2.4(15-22/3)). Since a nonblocking-static expression has to be of a Boolean type, we don't need the other cases (membership, equality/ordering, and case expression). We could add the equality/ordering/membership cases here if the group thinks that for consistency is more important than keeping the size small. (conditional expressions would need a very different rule if we wanted it; the selector or conditions would have to be static and the dependent_expressions would have to be nonblocking-static.] AARM Reason: We define the term "nonblocking-static expression" so that nonblocking attribute references can be used to define the value of other nonblocking aspects, but that we don't allow anything with a value not known at compile-time. For a program unit, for a task entry, for a formal package, formal subprogram, formal object of an anonymous access-to-subprogram type, and for a named access-to-subprogram type (including a formal type), the following language-defined representation aspect is defined: Nonblocking The type of aspect Nonblocking is Boolean. When aspect Nonblocking is False for an entity, the entity might contain a potentially blocking operation; such an entity *allows blocking*. If the aspect is True for an entity, the entity is said to be *nonblocking*. This aspect is inherited by overridings of dispatching operations, unless directly specified. AARM Ramification: specifying Nonblocking as False imposes no requirements. Specifying Nonblocking as True imposes additional compile-time checks to prevent blocking, but does not prevent deadlock. A pragma Detect_Blocking can be used to ensure that Program_Error is raised in a deadlock situation. The Nonblocking aspect may be specified for all entities for which it is defined, except for protected operations and task entries. If directly specified, the aspect_definition shall be a nonblocking-static expression. For a generic instantiation, the aspect is determined by the setting for the generic unit[Redundant, re-evaluated based on the actual parameters.] If the aspect is directly specified for an instance, the value shall be confirming. AARM Ramification: The value for the generic unit might be different than that for the instance if it involves one or more Nonblocking attribute references. [Editor's note: I'm presuming that all of the contents of the instance are re-evaluated by the rules of 12.3. I didn't go look that up, so we might need a special rule to force that; but it would be the expected "macro" behavior.] For a (protected or task) entry, the value of the aspect is False. AARM Reason: An entry can be renamed as a procedure, so the value of the aspect has to be well-defined (as the attribute can be applied to a procedure). We do not want a nonblocking subprogram to be able to call an entry, no matter how it occurs, so the value ought to be False. Moreover, we do not want a subprogram that renames an entry to be able to override a nonblocking subprogram. We could have used individual rules for these cases, but there were already many of them, and this solution avoids the need for extra rules. For a predefined operator of an elementary type. and for the predefined ordering operators of an array type, the value of the aspect is True. For predefined equality operators of composite types, the value of the aspect is False. AARM Reason: Record equality can be composed of operations including user-defined "=" operators, which might allow blocking. Array equality might use some record equality. We can't introduce an incompatibility here, so we have to assume the worst. [Editor's note: We might be able to do better here for untagged types (inc. arrays) by examining the type definition, but sadly for tagged types we have to allow it to be blocking as some overriding might need that (and all of the overridings need to be the same). As such, we do not bother with the extra complexity of rules to allow some record equality to be nonblocking.] ** ARG wants this changed, but how??? Note that this says that the "=" of a partial view has the value False, and the "=" of a completing elementarary type has True, which isn't going to work. For any other program unit, formal package, formal subprogram, formal object, or (formal) access-to-subprogram type, the aspect is determined by the setting for the innermost program unit enclosing the entity. If not specified for a library unit, the default is True if the library unit is declared pure and is not a generic unit, and False otherwise. A nonblocking program unit shall not contain, other than within nested units with Nonblocking specified as False, a call on a callable entity for which the Nonblocking aspect is False, nor shall it contain any of the following: * a select_statement; * an accept_statement; * a delay_statement; * an abort_statement; * task creation or activation. AARM Ramification: Implicit calls for finalization, storage pools, and the like are covered by the above prohibition. The rules above say "a call", not "an explicit call". Such calls are considered statically bound when that is possible, that is when the controlling object has a known specific type (even if the actual implementation uses dispatching). AARM Discussion: We don't need to specially worry about subprograms of limited interfaces that are implemented by entries, as any such subprogram necessarily has the value False for the Nonblocking aspect, and thus is already covered by the prohibition against calling such subprograms. Similarly, we don't need to worry specially about entry calls, as they will be detected by the prohibition against calls to entities with the Nonblocking aspect False. End AARM Discussion. For the purposes of the above rule, an entry_body is considered nonblocking if the immediately enclosing protected unit is nonblocking. AARM Reason: An entry always allows blocking (by rule); but we want to be able to compile-time check for most violations of prohibition against potentially blocking operations in a protected action (see 9.5.1). We do that by using the nonblocking status of the protected unit as the controlling factor, and enforce that by not allowing the specification of the Nonblocking aspect for any protected operation. A subprogram shall be nonblocking if it overrides a nonblocking dispatching operation. An entry shall not implement a nonblocking procedure. AARM Discussion: Rules elsewhere in the standard (4.6 and 3.10.2) ensure that access-to-subprogram conversion and the Access attribute enforce nonblocking. AARM Ramification: A nonblocking subprogram can override one that allows blocking, but the reverse is illegal. Thus one can declare a Finalize subprogram to be nonblocking, even though it overrides a routine that allows blocking. (This works as a nonblocking subprogram allows a strict subset of the operations allowed in allows blocking subprograms, so calling such a subprogram as if it allows blocking -- as is necessary in a dispatching call -- is harmless.) In a generic instantiation: * the actual subprogram corresponding to a nonblocking formal subprogram shall be nonblocking Redundant[(an actual that is an entry is not permitted in this case)]; * the actual type corresponding to a nonblocking formal access-to-subprogram type shall be nonblocking; * the actual object corresponding to a formal object of a nonblocking access-to-subprogram type shall be of a nonblocking access-to-subprogram type; * the actual instance corresponding to a nonblocking formal package shall be nonblocking. In addition to the places where Legality Rules normally apply (see 12.3), the above rules apply also in the private part of an instance of a generic unit. AARM Ramification: For a generic formal parameter to be nonblocking (thus, for these rules to apply), either it or some enclosing unit has to explicitly specify aspect Nonblocking to be True. In particular, these rules do not apply when it or some enclosing unit specifies aspect Nonblocking to be an expression involving attribute Nonblocking of a generic formal parameter (see below). However, in such a case, these rules do apply in the instance of the specification of the generic unit (the normal re-checking is needed). For instance, the body of an expression function might make a prohibited call. For a prefix S that denotes a subprogram (including a formal subprogram): S'Nonblocking Denotes whether subprogram S is considered nonblocking; the value of this attribute is of type Boolean. The prefix S shall statically denote a subprogram. AARM Ramification: The evaluation of the prefix S will have no effect, which is necessary for S'Nonblocking to be static. For the intended use in aspect specifications, we don't want any evaluation, as it would happen at some freezing point. If S denotes a formal subprogram of a generic unit G, the value of S'Nonblocking is True within the body of G or within the body of a generic unit declared within the declarative region of G, and False otherwise. Otherwise, S'Nonblocking returns the value of the Nonblocking aspect of S. AARM Reason: Inside the generic body of G (and the bodies of generic child units of G), we assume the worst about S'Nonblocking, so we enforce the nonblocking restrictions on entities that use it to define their own nonblocking aspect. In the specification of G, we assume-the-best and expect the Legality Rules (all of them) to be rechecked in the instance. This does not impose any requirement on the formal subprogram (that can be done by specifying the value of the aspect). AARM To Be Honest: In an instance, S'Nonblocking returns the value of the nonblocking aspect of the actual subprogram, even if referenced through the name of the formal. For a prefix P that denotes a package (including a formal package): P'Nonblocking Denotes whether package P is considered nonblocking; the value of this attribute is of type Boolean. If P denotes a formal package of a generic unit G, the value of P'Nonblocking is True within the body of G or within the body of a generic unit declared within the declarative region of G, and False otherwise. Otherwise, P'Nonblocking returns the value of the Nonblocking aspect of P. For a prefix S that denotes an access-to-subprogram subtype (including formal access-to-subprogram subtypes): S'Nonblocking Denotes whether a subprogram designated by a value of type S is considered nonblocking; the value of this attribute is of type Boolean. [Editor's note: The following is moved from 9.5.1, including the AARM notes with minimal changes. The entry_call_statement rule had been previously identified as needing a change (it's really broken, having nothing specifically to do with this AI).] The following are defined to be *potentially blocking* operations: AARM Reason: The primary purpose of these rules is to define what operations are not allowed in a protected operation (blocking is not allowed). Some of these operations are not directly blocking. However, they are still treated as potentially blocking, because allowing them in a protected action might impose an undesirable implementation burden. * a select_statement; * an accept_statement; * an entry_call_statement, or a call on a procedure that renames or is implemented by an entry; * a delay_statement; * an abort_statement; * task creation or activation; * an external call on a protected subprogram (or an external requeue) with the same target object as that of the protected action; AARM Reason: This is really a deadlocking call, rather than a blocking call, but we include it in this list for simplicity. * a call on a subprogram whose body contains a potentially blocking operation. AARM Reason: This allows an implementation to check and raise Program_Error as soon as a subprogram is called, rather than waiting to find out whether it actually reaches the potentially blocking operation. [Editor's notes: End mostly unchanged text. I considered trying to unify Nonblocking and potentially blocking further, but that seemed messy and error-prone. One could imagine replacing the last rule with "a call on a subprogram with Nonblocking = False", but that would expose a lot of existing code to a Bounded Error (since the default for Nonblocking is False, and that has to be the case for compatibility).] Language-defined subprograms for which the Nonblocking aspect has the value False [Redundant: (whether explicitly or by inheritance)] are potentially blocking. [Editor's note: This is what remains of 9.5.1(18). The old definition should be reflected in the aspect values for language-defined routines.] Modify 9.5.1(8): During a protected action, it is a bounded error to invoke an operation that is potentially blocking.[ The following are defined to be potentially blocking operations:] [Editor's note: This is no longer a definition for potentially blocking.] Delete 9.5.1(9-16, 18) and the associated AARM notes. Replace note 9.5.1(22.1/2) with: The aspect Nonblocking can be specified True on the definition of a protected unit in order to reject most attempts to use potentially blocking operations within the protected unit (see 9.5). The pragma Detect_Blocking may be used to ensure that any remaining executions of potentially blocking operations during a protected action raise Program_Error. See H.5. AARM Discussion: The deadlock case cannot be detected at compile-time, so pragma Detect_Blocking is needed to give it consistent behavior. Modify 3.10.2(33/3): [Part of the definition of the Access attribute for subprograms] ... The accessibility level of P shall not be statically deeper than that of S. {If S is nonblocking, P shall be nonblocking. }In addition to the places where Legality Rules normally apply (see 12.3), {these rules apply}[this rule applies] also in the private part of an instance of a generic unit. Add after 4.6(24.21/4): [Type conversion Legality Rules for access-to-subprogram types] * If the target type is nonblocking, the operand type shall be nonblocking. Modify the AARM Note 13.1(9.d/3): ...most aspects do not need this complexity[ (including all language-defined aspects as of this writing)], we avoid the complexity... [Editor's note: This and the next couple of changes are needed as Nonblocking can be specified on generic formal parameters, and it surely is language-defined. In this particular case, the rule itself is fine (it says "Unless otherwise specified...").] Delete "a generic_formal_parameter_declaration" from 13.1.1(17/4) [since we allow specifying Nonblocking on formals.] Modify the AARM Note 13.1.1(17.a/3): Implementation-defined aspects can be allowed on these, of course; the implementation will need to define the semantics. In {addition}[particular], {the language does not define default aspect matching rules for generic formals; only the handful of aspects allowed on formals have such rules. Therefore,} the implementation will need to define actual [type] matching rules for any aspects allowed on formal types[; there are no default matching rules defined by the language.] Add after 13.13.2(37/1): The default implementations of stream-oriented attributes has the value False for aspect Nonblocking. AARM Reason: The underlying Read/Write operations are called via dispatching calls. Since we cannot afford any incompatibility with existing Ada code, the stream operations allow blocking. Thus the stream-oriented attributes must allow blocking as well. Wording for definition of language-defined packages and subprograms is TBD. [Editor's note: We intend that language-defined subprograms are nonblocking unless this Standard says otherwise. Specifically, 9.5.1(18) said (before we deleted it above): Certain language-defined subprograms are potentially blocking. In particular, the subprograms of the language-defined input-output packages that manipulate files (implicitly or explicitly) are potentially blocking. Other potentially blocking subprograms are identified where they are defined. When not specified as potentially blocking, a language-defined subprogram is nonblocking. Non-generic units that are pure are automatically nonblocking as specified in 9.5 (these are noted below). Other units should explicitly have Nonblocking specified. We'll handle the containers in AI12-0112-1 (the AI that defines preconditions for the container operations); it probably makes the most sense to add all of the contracts at once for those. The entire list of non-container units is: Ada.Assertions — 11.4.2 - Pure Ada.Asynchronous_Task_Control — D.11 - Nonblocking => True Ada.Calendar — 9.6 - Nonblocking => True Ada.Calendar.Arithmetic — 9.6.1 - Nonblocking => True Ada.Calendar.Formatting — 9.6.1 - Nonblocking => True Ada.Calendar.Time_Zones — 9.6.1 - Nonblocking => True Ada.Characters — A.3.1 - Pure Ada.Conversions — A.3.4 - Pure Ada.Handling — A.3.2 - Pure Ada.Latin_1 — A.3.3 - Pure Ada.Command_Line — A.15 - Nonblocking => True Ada.Complex_Text_IO — G.1.3 - Nonblocking => False (** String routines) Ada.Decimal — F.2 - Pure Ada.Direct_IO — A.8.4 - Nonblocking => False (I/O) Ada.Directories — A.16 - Nonblocking => False (I/O) - Full_Name through Compose should have Nonblocking => True (as they are just string manipulation routines). Ada.Directories.Hierarchical_File_Names — A.16.1 - Nonblocking => True (these are all string manipulation routines). Ada.Directories.Information — A.16 - (**** Impl def) Ada.Dispatching — D.2.1 - Nonblocking => False (For Yield by the second sentence of D.2.1(7/3), which should be deleted. There are no other subprograms here.) Ada.Dispatching.EDF — D.2.6 - Nonblocking => False ??? -- The language doesn't say either way, but at a minimum Delay_Until_and_Set_Deadline has to be potentially blocking. -- Since Set_Deadline causes a task dispatching point by D.2.6(19/2), it at least causes premption, so it seems to be potentially blocking as well. -- Get_Deadline probably ought not be potentially blocking. Asked Alan. Ada.Dispatching.Non_Preemptive — D.2.4 - Nonblocking => True -- AARM Note D.2.4(2.b/3) confirms this for Yield_to_Higher. Yield_to_Same_or_Higher is a rename, and gets the value from the original routine. Ada.Dispatching.Round_Robin — D.2.5 - Nonblocking => True ??? -- No explicitly defined potentially blocking routines, and the semantics don't seem to require any. Asked Alan. Ada.Dynamic_Priorities — D.5.1 - Nonblocking => True ??? -- No explicitly defined potentially blocking routines. Asked Alan. Ada.Environment_Variables — A.17 - Nonblocking => True Ada.Exceptions — 11.4.1 - Nonblocking => True Ada.Execution_Time — D.14 - Nonblocking => True Ada.Execution_Time.Group_Budgets — D.14.2 - Nonblocking => True Ada.Execution_Time.Interrupts — D.14.3 - Nonblocking => True Ada.Execution_Time.Timers — D.14.1 - Nonblocking => True Ada.Finalization — 7.6 - Nonblocking => False (*** user overriding) Ada.Float_Text_IO — A.10.9 - Nonblocking => False (** String routines) Ada.Float_Wide_Text_IO — A.11 - Nonblocking => False (** String routines) Ada.Float_Wide_Wide_Text_IO — A.11 - Nonblocking => False (** String routines) Ada.Integer_Text_IO — A.10.8 - Nonblocking => False (** String routines) Ada.Integer_Wide_Text_IO — A.11 - Nonblocking => False (** String routines) Ada.Integer_Wide_Wide_Text_IO — A.11 - Nonblocking => False (** String routines) Ada.Interrupts — C.3.2 - Nonblocking => True Ada.Interrupts.Names — C.3.2 - (**** Impl def) Ada.IO_Exceptions — A.13 - Pure Ada.Iterator_Interfaces — 5.5.1 - Nonblocking => False (this declares interfaces used elsewhere, and we have to allow blocking in the -- implemented routines. This is annoying; we may have to make a separate nonblocking version for the parallel stuff) Ada.Locales — A.19 - Nonblocking => True Ada.Numerics — A.5 - Pure Ada.Numerics.Complex_Arrays — G.3.2 - Pure Ada.Numerics.Complex_Elementary_Functions — G.1.2 - Pure Ada.Numerics.Complex_Types — G.1.1 - Pure Ada.Numerics.Discrete_Random — A.5.2 - Nonblocking => True Ada.Numerics.Elementary_Functions — A.5.1 - Pure Ada.Numerics.Float_Random — A.5.2 - Nonblocking => True Ada.Numerics.Generic_Complex_Arrays — G.3.2 - Nonblocking => True (generic with formal packages, but all matching instances have to have Nonblocking True) Ada.Numerics.Generic_Complex_Elementary_Functions — G.1.2 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Numerics.Generic_Complex_Types — G.1.1 - Nonblocking => True (Pure but generic) Ada.Numerics.Generic_Elementary_Functions — A.5.1 - Nonblocking => True (Pure but generic) Ada.Numerics.Generic_Real_Arrays — G.3.1 - Nonblocking => True (Pure but generic) Ada.Numerics.Real_Arrays — G.3.1 - Pure Ada.Real_Time — D.8 - Nonblocking => True Ada.Real_Time.Timing_Events — D.15 - Nonblocking => True (confirmed by note D.15(48/2)). Ada.Sequential_IO — A.8.1 - Nonblocking => False (I/O) Ada.Storage_IO — A.9 - Nonblocking => False (I/O) Ada.Streams — 13.13.1 - Nonblocking => False (*** user overriding) Ada.Streams.Stream_IO — A.12.1 - Nonblocking => False (I/O) Ada.Strings — A.4.1 - Pure Ada.Strings.Bounded — A.4.4 - Nonblocking => True Ada.Strings.Bounded.Equal_Case_Insensitive — A.4.10 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Bounded.Hash — A.4.9 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Bounded.Hash_Case_Insensitive — A.4.9 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Bounded.Less_Case_Insensitive — A.4.10 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Fixed — A.4.3 - Nonblocking => True Ada.Strings.Fixed.Equal_Case_Insensitive — A.4.10 - Pure (from a rename) Ada.Strings.Fixed.Hash — A.4.9 - Pure Ada.Strings.Fixed.Hash_Case_Insensitive — A.4.9 - Pure Ada.Strings.Fixed.Less_Case_Insensitive — A.4.10 - Pure Ada.Strings.Equal_Case_Insensitive — A.4.10 - Pure Ada.Strings.Hash — A.4.9 - Pure Ada.Strings.Hash_Case_Insensitive — A.4.9 - Pure Ada.Strings.Less_Case_Insensitive — A.4.10 - Pure Ada.Strings.Maps — A.4.2 - Pure Ada.Strings.Maps.Constants — A.4.6 - Pure Ada.Strings.Unbounded — A.4.5 - Nonblocking => True Ada.Strings.Unbounded.Equal_Case_Insensitive — A.4.10 - Nonblocking => True Ada.Strings.Unbounded.Hash — A.4.9 - Nonblocking => True Ada.Strings.Unbounded.Hash_Case_Insensitive — A.4.9 - Nonblocking => True Ada.Strings.Unbounded.Less_Case_Insensitive — A.4.10 - Nonblocking => True Ada.Strings.UTF_Encoding — A.4.11 - Pure Ada.Strings.UTF_Encoding.Conversions — A.4.11 - Pure Ada.Strings.UTF_Encoding.Strings — A.4.11 - Pure Ada.Strings.UTF_Encoding.Wide_Strings — A.4.11 - Pure Ada.Strings.UTF_Encoding.Wide_Wide_Strings — A.4.11 - Pure Ada.Strings.Wide_Bounded — A.4.7 - Nonblocking => True Ada.Strings.Wide_Bounded.Wide_Equal_Case_Insensitive — A.4.7 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Wide_Bounded.Wide_Hash — A.4.7 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Wide_Bounded.Wide_Hash_Case_Insensitive — A.4.7 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Wide_Equal_Case_Insensitive — A.4.7 - Pure Ada.Strings.Wide_Fixed — A.4.7 - Nonblocking => True Ada.Strings.Wide_Fixed.Wide_Equal_Case_Insensitive — A.4.7 - Pure (from a rename) Ada.Strings.Wide_Fixed Wide_Hash — A.4.7 - Pure Ada.Strings.Wide_Fixed Wide_Hash_Case_Insensitive — A.4.7 - Pure Ada.Strings.Wide_Hash — A.4.7 - Pure Ada.Strings.Wide_Hash_Case_Insensitive — A.4.7 - Pure Ada.Strings.Wide_Maps — A.4.7 - Nonblocking => True Ada.Strings.Wide_Maps.Wide_Constants — A.4.7 - Nonblocking => True Ada.Strings.Wide_Unbounded — A.4.7- Nonblocking => True Ada.Strings.Wide_Unbounded.Wide_Equal_Case_Insensitive — A.4.7- Nonblocking => True Ada.Strings.Wide_Unbounded.Wide_Hash — A.4.7- Nonblocking => True Ada.Strings.Wide_Unbounded.Wide_Hash_Case_Insensitive — A.4.7- Nonblocking => True Ada.Strings.Wide_Wide_Bounded — A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Bounded.Wide_Wide_Equal_Case_Insensitive — A.4.8 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Wide_Wide_Bounded.Wide_Wide_Hash — A.4.8 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Wide_Wide_Bounded.Wide_Wide_Hash_Case_Insensitive — A.4.8 - Nonblocking => True (generic with a formal package, but all matching instances have to have Nonblocking True) Ada.Strings.Wide_Wide_Equal_Case_Insensitive — A.4.8 - Pure Ada.Strings.Wide_Wide_Fixed — A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Fixed.Wide_Wide_Equal_Case_Insensitive — A.4.8 - Pure (from a renames) Ada.Strings.Wide_Wide_Fixed.Wide_Wide_Hash — A.4.8 - Pure Ada.Strings.Wide_Wide_Fixed.Wide_Wide_Hash_Case_Insensitive — A.4.8 - Pure Ada.Strings.Wide_Wide_Hash — A.4.8 - Pure Ada.Strings.Wide_Wide_Hash_Case_Insensitive - A.4.8 - Pure Ada.Strings.Wide_Wide_Maps — A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Maps.Wide_Wide_Constants — A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Unbounded — A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Unbounded.Wide_Wide_Equal_Case_Insensitive — A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Unbounded.Wide_Wide_Hash — A.4.8 - Nonblocking => True Ada.Strings.Wide_Wide_Unbounded.Wide_Wide_Hash_Case_Insensitive — A.4.8 - Nonblocking => True Ada.Synchronous_Barriers — D.10.1 - Nonblocking => True (Wait_For_Release has Nonblocking => False by D.10.1(14/3); that paragraph should be deleted). Ada.Synchronous_Task_Control — D.10 - Nonblocking => True (Suspend_Until_True has Nonblocking => False by D.10(10), that sentence should be deleted). Ada.Synchronous_Task_Control.EDF — D.10 - Nonblocking => False (by D.10(10.1/3), that sentence should be deleted.) Ada.Tags — 3.9 - Nonblocking => True Ada.Tags.Generic_Dispatching_Constructor — 3.9 - Nonblocking => Constructor'Nonblocking (* generic) Ada.Task_Attributes — C.7.2 - Nonblocking => True Ada.Task_Identification — C.7.1 - Nonblocking => True (Abort_Task has Nonblocking => False by C.7.1(16); that paragraph should be deleted) Ada.Task_Termination — C.7.3 - Nonblocking => True Ada.Text_IO — A.10.1 - Nonblocking => False (** String routines) Ada.Text_IO.Bounded_IO — A.10.11 - Nonblocking => Bounded'Nonblocking (* generic) Ada.Text_IO.Complex_IO — G.1.3 - Nonblocking => Complex_Types'Nonblocking (* generic) Ada.Text_IO.Editing — F.3.3 - Nonblocking => False (** String routines) Ada.Text_IO.Text_Streams — A.12.2 - Nonblocking => False Ada.Text_IO.Unbounded_IO — A.10.12 - Nonblocking => False Ada.Unchecked_Conversion — 13.9 - Nonblocking => True (Pure but generic) Ada.Unchecked_Deallocate_Subpool — 13.11.5 - Nonblocking => False (*** user calls) Ada.Unchecked_Deallocation — 13.11.2 - Nonblocking => True Ada.Wide_Characters — A.3.1 - Pure Ada.Wide_Characters.Handling — A.3.5 - Pure Ada.Wide_Text_IO — A.11 - Nonblocking => False (** String routines) Ada.Wide_Text_IO.Complex_IO — G.1.4 - Nonblocking => Complex_Types'Nonblocking (* generic) Ada.Wide_Text_IO.Editing — F.3.4 - Nonblocking => False (** String routines) Ada.Wide_Text_IO.Text_Streams — A.12.3 - Nonblocking => False Ada.Wide_Text_IO.Wide_Bounded_IO — A.11 - Nonblocking => Wide_Bounded'Nonblocking (* generic) Ada.Wide_Text_IO.Wide_Unbounded_IO — A.11 - Nonblocking => False Ada.Wide_Wide_Characters — A.3.1 - Pure Ada.Wide_Wide_Characters.Handling — A.3.6 - Pure Ada.Wide_Wide_Text_IO — A.11 - Nonblocking => False (** String routines) Ada.Wide_Wide_Text_IO.Complex_IO — G.1.4 - Nonblocking => Complex_Types'Nonblocking (* generic) Ada.Wide_Wide_Text_IO.Editing — F.3.4 - Nonblocking => False (** String routines) Ada.Wide_Wide_Text_IO.Text_Streams — A.12.3 - Nonblocking => False Ada.Wide_Wide_Text_IO.Wide_Wide_Bounded_IO — A.11 - Nonblocking => Wide_Wide_Bounded'Nonblocking (* generic) Ada.Wide_Wide_Text_IO.Wide_Wide_Unbounded_IO — A.11 - Nonblocking => False Interfaces — B.2 - Pure Interfaces.C — B.3 - Pure Interfaces.C.Pointers — B.3.2 - Nonblocking => True Interfaces.C.Strings — B.3.1 - Nonblocking => True Interfaces.COBOL — B.4 - Nonblocking => True Interfaces.Fortran — B.5 - Pure System — 13.7 - Pure System.Address_To_Access_Conversions — 13.7.2 - Nonblocking => True System.Machine_Code — 13.8 - (**** Impl def) System.Multiprocessors — D.16 - Nonblocking => True System.Multiprocessors.Dispatching_Domains — D.16.1 - Nonblocking => True System.RPC — E.5 - Nonblocking => False (E.5(23) says this explicitly; that paragraph should be deleted.) System.Storage_Elements — 13.7.1 - Pure System.Storage_Pools — 13.11 - Nonblocking => False (*** user overriding) System.Storage_Pools.Subpools — 13.11.4 - Nonblocking => False (*** user overriding) Items marked "Pure" are pure, and thus automatically are Nonblocking. Items marked "(* generic)" have Nonblocking given as a formula. This automatically matches the nonblocking setting to that of the actual parameters (see the !discussion for more on this). Items marked "(** String routines)" have Get/Put routines that operate only on Strings -- those explicitly have Nonblocking => True specified. That's in accordance with the AARM note 9.5.1(18.a) (and an old AI). Items marked "(*** user overriding)" are mainly used to provide a framework for user code (as in storage pools or streams). Since all dispatching calls have to have the same value for nonblocking, and we have to keep compatibility with existing Ada code, we cannot make such packages (and types) nonblocking. Items marked "(*** user calls)" make calls on code that is potentially user-defined via dispatching. These usually work in conjunction with types declared in packages associated with the previous item. Items marked "(**** impl def)" have implementation-defined contents, so we need say nothing. End lengthy editor's note.] !discussion We considered changing the aspect name from "Nonblocking" to "Potentially_Blocking," as that matches RM terminology better, but we ultimately concluded that would be a mistake. Furthermore, "nonblocking" is used in 9.5.1, albeit somewhat informally. Were we to switch to Potentially_Blocking, the default would be True rather than False, which is unlike other Boolean aspects. Furthermore, with Potentially_Blocking => True, we wouldn't *require* that it be potentially blocking, merely allow it. Perhaps Allow_Blocking would be better, but that doesn't match RM terminology at all, and still has the "wrong" default. We initially modeled this aspect after No_Return, which has a somewhat similar purpose and presumably has already worked out some of the needed rules. However, we have gone beyond that, because we now have nonblocking access-to-subprogram types, nonblocking formal subprograms, etc. The rules do not allow calling "normal" subprograms from a nonblocking subprogram. This allows detecting any potentially blocking operations used in a nonblocking subprogram statically. This is important if pragma Detect_Blocking is used, as such detection is required. (Otherwise, this is just a bounded error and the "mistake" can be ignored with the usual consequences.) We have provided package-level defaults, given that many packages will have all of their subprograms non-blocking. We chose to make the default for a declared pure, non-generic library unit to be nonblocking, as that is almost always the case, since blocking typically implies the use of some kind of global lock. We do not foresee significant incompatibilities, since declared pure library units may only depend on other declared pure library units. For pure generic units we leave the default at False for compatibility reasons, because these might have existing instances where an actual subprogram (or access-to-subprogram type) is potentially blocking. We did not specify that protected subprograms are by default Nonblocking=>True, since that would be incompatible, as they then could not call subprograms with a default Nonblocking aspect value of False. It might be possible to specify Nonblocking=>True as the default for protected subprograms in a future version of the standard (and clearly an implementation could at least provide a warning when a call is made to a subprogram with Nonblocking of False). Because of the confusion related to the fact that protected operations are always required to be nonblocking at run-time, we don't allow specifying the attribute directly on an individual protected operation. However, we allow specifying Nonblocking on a protected unit to determine the setting for all of the enclosed protected operations. We only allow specifying a confirming value of Nonblocking on a generic instantiation; the value of the aspect comes from the generic unit (possibly after re-evaluating the aspect based on the values of the actual parameters). Specifying a different value would simply be confusing, as it wouldn't change the enforcement of Legality Rules in the generic unit (and it would be wrong to supply a value of True for an instance of a unit that have the value of False, as in that case no rules would have been enforced in the body). ---- The attribute Nonblocking is primarily useful for use in the Nonblocking aspect of other subprograms, and mainly for the non-blocking property of formal subprograms. We allow the prefix to be any subprogram to avoid having special cases, and as it may be useful to ensure that a group of subprograms all have the same contract. In the case of nonblocking, that could be accomplished with a constant, but in the case of other static contracts that we are considering like exception contracts (AI12-0015-1) and global contracts (AI12-0079-1), a mechanism to copy them will be valuable (especially as they may be lengthy). As we want all of the contracts to work as similarly as possible, we make the attribute Nonblocking as general as possible. The primary use for this attribute is in aspects of generic units. The attribute makes it possible for a generic unit to have a nonblocking aspect that depends on those of the actual subprograms. That's especially important for the containers, which we want to be primarily nonblocking. This mechanism takes some effort for the implementer of a generic unit, but it means that the instantiator of such a unit does not need to worry about nonblocking, as the most restrictive setting compatable with the actual subprograms will automatically be chosen. Unfortunately, this mechanism doesn't have an obvious extension to support anonymous access-to-subprogram parameters; the type is anonymous and the actual is typically an Access attribute. One could imagine allowing the prefix to be a parameter, something like: procedure Iterate (Container : in Hashed_Maps; Process : not null access procedure (Position : in Cursor) when Nonblocking => Process'Nonblocking and Hash'Nonblocking and Equivalent_Keys'Nonblocking); But in that case the Nonblocking value would have to be determined based on the actuals of the call; it would be weird for the Legality of a call to depend on the details of actual parameters. Thus we didn't propose such a mechanism. ---- We could simplify this proposal further by dropping the ability to specify Nonblocking on generic formal parameters, and just depending on the Nonblocking attribute to handle that. That would eliminate the rules about generic formal matching. We didn't do that as that would require having nonblocking attributes for formal objects (which would reduce the value somewhat), and would eliminate the "easy" solution for new code (which is to simply require everything to be nonblocking). Not everyone needs to write the most flexible possible generics. --- Comparing Alternative 1 with this proposal. The problem with alternative 1 is that a generic unit like the containers can be set to nonblocking, but then using this with an allows blocking routine requires an explicit override by the user on the instance. Since the default for most routines is that they are not nonblocking, this could provide a significant compatibility problem. An alternative for alternative 1 would be to declare units like the containers to be blocking; but then they can never be nonblocking (and we surely want to use them as nonblocking). In contrast, this proposal puts all of the burden on the implementer of a package (where it should be) and none on the user of the package. Alternative 1 is definitely easier for the implementer of a package, and harder for a user. Container usage examples: Imagine that a user has an existing user-defined Hash function: subtype Label is String (1..10); function Hash (Key : in Label) return Ada.Containers.Hash_Type; With this proposal (as outlined in the example section below), if they don't care about nonblocking (as is likely to be the case for recompiling existing code), their existing instantation will compile with no problem: package My_Hashed_Map is new Ada.Containers.Hashed_Map (Label, Element, Hash, "="); If they do care about blocking behavior, they can add Nonblocking to Hash and they will get the Nonblocking behavior they want: function Hash (Key : in Label) return Ada.Containers.Hash_Type with Nonblocking => True; Alternatively, they could declare the instance to be Nonblocking: package My_Hashed_Map is new Ada.Containers.Hashed_Map (Label, Element, Hash, "=") with Nonblocking => True; which would cause an error (as Nonblocking is False), hopefully with an error message that Hash has Nonblocking set as False (since that's the default). With a good error message, the correct fix should be easy to find. ------------------- For alternative 1 (as described in AI12-0064-1/05), the situation is different. The original instantation of: package My_Hashed_Map is new Ada.Containers.Hashed_Map (Label, Element, Hash, "="); is now illegal, as Hash has Nonblocking = False, and that fails to match the default for the formal parameter Hash (which is Nonblocking => True). Thus the user has to change their code and add Nonblocking => True to Hash or add Nonblocking => False to the instance My_Hashed_Map. That doesn't seem good. If the default of Ada.Containers.Hashed_Map is changed to False, then the above works, but there no longer is any way to get a Nonblocking container. package My_Hashed_Map is new Ada.Containers.Hashed_Map (Label, Element, Hash, "=") with Nonblocking => True; should be illegal in this case, as the restrictions were not enforced in the generic body. --------------- There is one known problem with this proposal as it is written. The prefix of the Nonblocking attribute has to resolve without any context. That means that in many circumstances, overloaded prefixes aren't going to be usable. That could be a problem for operators (like "=" in the containers) that are widely used. I considered using subprogram calls rather than subprogram names in the prefix, but that ran into issues both with having appropriate parameters to use (in the generic case) and with evaluation of the prefix (which we don't want to do). I also considered using qualification, but that doesn't help for relational operators (they all return Boolean!). It's possible to rename operators to unique names, so the problem isn't unsurmountable, but of course that clutters the name space of packages. (We can use renames as aspects aren't resolved until the freezing point.) One of course can avoid using operators in generic specifications, but that's impractical for existing generics and a usage pain for new generics. !example package Ada.Text_IO with Nonblocking => False is ... generic type Enum is (<>); package Enumeration_IO is -- implicitly Nonblocking => False Default_Width : Field := 0; Default_Setting : Type_Set := Upper_Case; procedure Get(File : in File_Type; -- implicitly Nonblocking => False ... procedure Get(From : in String; Item : out Enum; Last : out Positive) with Nonblocking => True; -- explicitly Nonblocking => True procedure Put(To : out String; Item : in Enum; Set : in Type_Set := Default_Setting) with Nonblocking => True; -- explicitly Nonblocking => True end Enumeration_IO ... end Ada.Text_IO; with Ada.Iterator_Interfaces; generic type Key_Type is private; type Element_Type is private; with function Hash (Key : Key_Type) return Hash_Type; with function Equivalent_Keys (Left, Right : Key_Type) return Boolean; with function "=" (Left, Right : Element_Type) return Boolean is <>; package Ada.Containers.Hashed_Maps is with Nonblocking => Hash'Nonblocking and Equivalent_Keys'Nonblocking and Element_Equal'Nonblocking; pragma Preelaborate(Hashed_Maps); pragma Remote_Types(Hashed_Maps); function Element_Equal (Left, Right : Element_Type) return Boolean renames "="; -- Rename of formal "=". ... procedure Iterate (Container : in Map; Process : not null access procedure (Position : in Cursor)) with Nonblocking => False; ... end Ada.Containers.Hashed_Maps; Alternatively, we could separately specify the blocking for the individual routines, depending on which of the formal routines they are allowed to use. (Given that we leave that unspecified in the Standard, it's probably better to use a global setting as was done here.) !ASIS TBD. !ACATS test ACATS B-Tests and C-Tests. !appendix From: Randy Brukardt Sent: Thursday, June 2, 2016 7:59 PM At the Vermont meeting, I was asked to create an alternative to Tucker's Nonblocking proposal using an attribute to specify nonblocking for generics. I did that back in December and sent it off to Tucker for comment. After waiting slightly less than 167 days (and sending between 3-6 reminders, depending on how one counts) [but who's counting :-)] without receiving any reply or even acknowledgement, I've decided to stop waiting and submit a slightly revised draft to the entire group in the hopes of getting comments. [This is version /02 - Ed.] While I'm convinced this is better (especially for compatibility with the existing containers), it probably can be improved further (and there were a handful of areas that I didn't figure out in detail). **************************************************************** From: Jean-Pierre Rosen Sent: Friday, June 3, 2016 12:36 AM > If not specified for a library unit, the default is True if the > library unit is declared pure and is not a generic unit, and > False otherwise. I was wondering about Shared_Passive units. Reading further, I realize that SP units can call protected subprograms (if the PO has no entries), and those are not Nonblocking. Maybe an extra reason for making protected subprograms nonblocking... **************************************************************** From: Tucker Taft Sent: Friday, June 3, 2016 8:46 AM Sorry for being so slow. This upcoming weekend is set aside as my "ARG" weekend. It has been really hard for me to find time before now to focus on the ARG issues. **************************************************************** From: Tucker Taft Sent: Sunday, June 5, 2016 11:15 AM Sorry for the late reply. This looks good to me. For AI12-0079 I think I will steal the notion of an attribute of generic formals to specify more precisely the Global aspect for generic code, as there is a very similar problem there, and a similar solution seems appropriate. **************************************************************** From: Steve Baird Sent: Thursday, October 20, 2016 8:22 PM In private mail, I wrote: > Language design principle: > If an expression in a generic is static, then the > corresponding expression in an instance must also > be static and must have the same value. Note that I'm not quoting this LDP from the RM or anywhere else. Randy and I had a discussion of how violating this principle leads to pestilence, famine, and other bad things. This discussion can be repeated if anyone is interested. > > Which brings us to the Nonblocking attribute as described in > alternative 2, version 1.5 of ai12-0064 (I know we just discussed this > AI in Pittsburgh, but I don't recall any updates that are relevant to > today's question). > > We've got: > > For a prefix S that denotes a subprogram (including a formal > subprogram): > > S'Nonblocking > ...; the value > of this attribute ...is always static ... > > If S denotes a formal subprogram of a generic unit G, the value of > S'Nonblocking is True within the body of G or within the body of a > generic unit declared within the declarative region of G, and False > otherwise. > > ... > > In an instance, S'Nonblocking returns the value > of the nonblocking aspect of the actual subprogram, even if > referenced through the name of the formal. > > I think we have a problem here with a violation of the aforementioned > language design principle. Do folks agree that there is a problem here? I think this means that if the Nonblocking attribute of a generic formal subprogram is static, then the corresponding actual parameter must have a matching attribute value. There are several possible solutions which satisfy this but they each have drawbacks and would need to be discussed. For example, the Nonblocking attribute of a formal subprogram could be nonstatic and then an approach based on post-compilation rules (which could be checked at compile time by implementations which macro-expand instantiations) might work if combined with an idea Randy suggested, an almost-static expression which is non-static in a generic but will be static in any instance. **************************************************************** From: Tucker Taft Sent: Thursday, October 20, 2016 8:39 PM >> Language design principle: >> If an expression in a generic is static, then the >> corresponding expression in an instance must also >> be static and must have the same value. >> > > Note that I'm not quoting this LDP from the RM or anywhere else. > Randy and I had a discussion of how violating this principle leads to > pestilence, famine, and other bad things. > This discussion can be repeated if anyone is interested. I'd be somewhat interested, though I can imagine some weirdness if you capture the value of the attribute. I think we want to eliminate the notion it is "always static." We almost never say that sort of thing, and I think your principle about generics makes that unwise. I think more frequently we talk about assuming the "best" in the generic spec (and rechecking in the instance) while assuming the worst in the generic body. I suspect that that same approach can work here. >> ... We've got: >> >> For a prefix S that denotes a subprogram (including a formal >> subprogram): >> >> S'Nonblocking >> ...; the value >> of this attribute ...is always static ... >> >> If S denotes a formal subprogram of a generic unit G, the value of >> S'Nonblocking is True within the body of G or within the body of a >> generic unit declared within the declarative region of G, and False >> otherwise. >> >> ... >> >> In an instance, S'Nonblocking returns the value >> of the nonblocking aspect of the actual subprogram, even if >> referenced through the name of the formal. >> >> I think we have a problem here with a violation of the aforementioned >> language design principle. > > Do folks agree that there is a problem here? Yes, saying this is "static" in a generic seems unwise. I would rather use the "assume the best" and "assume the worst" approach. > For example, the Nonblocking attribute of a formal subprogram could be > nonstatic and then an approach based on post-compilation rules (which > could be checked at compile time by implementations which macro-expand > instantiations) might work if combined with an idea Randy suggested, > an almost-static expression which is non-static in a generic but will > be static in any instance. I think this is basically accomplishing something very similar to the assume the best/worst approach. Of course when you say "any instance" you mean any instance that is not itself nested within a generic. **************************************************************** From: Randy Brukardt Sent: Friday, October 21, 2016 12:18 PM ... > > For example, the Nonblocking attribute of a formal subprogram could > > be nonstatic and then an approach based on post-compilation rules > > (which could be checked at compile time by implementations which > > macro-expand > > instantiations) might work if combined with an idea Randy suggested, > > an almost-static expression which is non-static in a generic but > > will be static in any instance. > > I think this is basically accomplishing something very similar to the > assume the best/worst approach. Of course when you say "any instance" > you mean any instance that is not itself nested within a generic. That's (assume-the-worst/assume-the-best) is what the current rules are intended to accomplish. We essentially assume-the-worst about the value of the attribute in a generic body. What other way could work?? Steve completely ignored our lengthy e-mail discussion in this note, forcing me to reproduce the entire thing here (and wasting another 30 minutes). In particular, he ignored a far more important (in my view) Language Design Principle (LDP): If the value of an expression is needed to determine the result of a Legality Rule, the expression shall be static. (Again, I don't think this is ever expressed in the AARM, but it should be pretty obvious.) Since the entire point of attribute Nonblocking is to use it in aspect Nonblocking, which controls Legality Rules, this LDP also applies. Clearly one of these LDPs has to be extensively modified in order to make this work. Also note that it is critical that Nonblocking attributes can be combined in expressions for the aspect Nonblocking. (Usually with "and", but I'd hate to limit things that way.) They also need to be able to be combined with other static expressions (such as a global flag). Specifically, we need to know what rules to enforce inside of generics for cases like: procedure Foo (...) with Nonblocking => Bar'Nonblocking and Glarch'Nonblocking and Some_Global_Nonblocking_Setting; The only solutions I see are far too heavy: The best I can do is to define something akin to a predicate-static expression (which I jokingly called a Steve_Baird_not_quite_memorial_and_not_quite_static_expression), and then such an expression would be allowed (by fiat) in aspect Nonblocking. LDP #2 would be modified to include the new kind of expression. That's awfully heavy. (*) The alternative of some sort of assume-the-worst fiat for a specified aspect Nonblocking and dropping the requirement for the expression to be static doesn't really work: it doesn't make sense if the expression is statically False (and the expression could be complicated and involve attributes Nonblocking from nongeneric units), and moreover we'd still have to somehow prevent procedure Foo with Nonblocking => Some_Function(42); Once you've handled those issues, you're pretty much back to the other solution (just with more wording). So as far as I can tell, this kills Nonblocking unless some other solution can be found. (*) Here's the actual joke wording that I proposed: A Steve_Baird_not_quite_memorial_and_not_quite_static_expression is * A non-static Nonblocking attribute (that is, one given inside of a generic that depends on a formal parameter); or * A static expression; or * A combination of two Steve_Baird_not_quite_memorial_and_not_quite_static_expressions with a logical binary operator; or * The "not" operator applied to a Steve_Baird_not_quite_memorial_and_not_quite_static_expression. We'd also have to define precisely which Nonblocking attributes are non-static, both here and in 4.9. (That alone will take a large number of words, because of the headaches of generic child units as well as nested generics.) We can get away with this little of a definition because we know that Nonblocking has type Boolean. (A complete definition would also include relational operators, but as they seem useless for type Boolean, I left them out.) There would be some value to a more general compile-time-known-but-not-static-expression (for 'Size of records, for instance), but that would be almost as much work to define as static expressions themselves. We'd have to come up with a better term. **************************************************************** From: Tucker Taft Sent: Friday, October 21, 2016 2:20 PM > ... >>> For example, the Nonblocking attribute of a formal subprogram could >>> be nonstatic and then an approach based on post-compilation rules >>> (which could be checked at compile time by implementations which >>> macro-expand >>> instantiations) might work if combined with an idea Randy suggested, >>> an almost-static expression which is non-static in a generic but >>> will be static in any instance. >> >> I think this is basically accomplishing something very similar to the >> assume the best/worst approach. Of course when you say "any >> instance" you mean any instance that is not itself nested within a >> generic. > > That's (assume-the-worst/assume-the-best) is what the current rules > are intended to accomplish. We essentially assume-the-worst about the > value of the attribute in a generic body. > > What other way could work?? I think making this static is unnecessary. We have other legality rules that depend on the best case or worst case, without requiring the value to be static. > Steve completely ignored our lengthy e-mail discussion in this note, > forcing me to reproduce the entire thing here (and wasting another 30 minutes). > > In particular, he ignored a far more important (in my view) Language > Design Principle (LDP): > > If the value of an expression is needed to determine the result of > a Legality Rule, the expression shall be static. > > (Again, I don't think this is ever expressed in the AARM, but it > should be pretty obvious.) I guess this is where I disagree. We can say that something is illegal if the value *might* possibly be a particular value at run-time. The *bounds* of what it might be needed to be known at compile time, but the actual value itself doesn't need to be static. We have a number of rules which are based on "known to be ..." sorts of things. > Since the entire point of attribute Nonblocking is to use it in aspect > Nonblocking, which controls Legality Rules, this LDP also applies. But it could apply only as a worst case or a best case, rather than by saying it is in fact static. > ... moreover we'd still have to somehow prevent > procedure Foo with Nonblocking => Some_Function(42); Once > you've handled those issues, you're pretty much back to the other > solution (just with more wording). I suspect we will end up going the same route as predicate static (as you mentioned), saying effectively that it must be an expression composed only of static subexpressions and 'Nonblocking attribute references. > So as far as I can tell, this kills Nonblocking unless some other > solution can be found. I don't see this as a "terminal" disease. Perhaps just a bit of the LDP "flu." **************************************************************** From: Randy Brukardt Sent: Friday, October 21, 2016 2:44 PM ... > > In particular, he ignored a far more important (in my view) Language > > Design Principle (LDP): > > > > If the value of an expression is needed to determine the result > > of a Legality Rule, the expression shall be static. > > > > (Again, I don't think this is ever expressed in the AARM, but it > > should be pretty obvious.) > > I guess this is where I disagree. We can say that something is > illegal if the value > *might* possibly be a particular value at run-time. The > *bounds* of what it might be needed to be known at compile time, but > the actual value itself doesn't need to be static. > We have a number of rules which are based on "known to be ..." sorts > of things. Sure, but none of those rules are based on the *value* of an expression (they're all other sorts of properties). > > Since the entire point of attribute Nonblocking is to use it in > > aspect Nonblocking, which controls Legality Rules, this LDP also applies. > > But it could apply only as a worst case or a best case, rather than by > saying it is in fact static. Surely; but that is just modifying the LDP to say "static or ". It doesn't invalidate the LDP in any way. > > ... moreover we'd still have to somehow prevent > > procedure Foo with Nonblocking => Some_Function(42); Once > > you've handled those issues, you're pretty much back to the other > > solution (just with more wording). > > I suspect we will end up going the same route as predicate static (as > you mentioned), saying effectively that it must be an expression > composed only of static subexpressions and 'Nonblocking attribute > references. Unless someone has a radical solution that doesn't cause other problems, it seems like the only sensible route. So, any ideas for the term to use?? I'll need something for the write-up, and "Steve Baird not quite memorial pseudo-static expression" probably doesn't work for most. :-) I suppose if we are going to use a one-time use term, we could copy the form of the "predicate-static" term and use "nonblocking-static". Other ideas? > > So as far as I can tell, this kills Nonblocking unless some other > > solution can be found. > > I don't see this as a "terminal" disease. Perhaps just a bit of the > LDP "flu." It going to add quite a bit of wording to a concept that already has altogether too much wording (and also I've been requested to try to figure out how to make it work for record equality, a topic that I punted on because it appeared so hard - that's also going to add a lot of wording). But I suppose it is always darkest before the dawn. (I just wonder if the sun is actually going to come up.) **************************************************************** From: Tucker Taft Sent: Friday, October 21, 2016 3:28 PM > ... I suppose if we are going to use a one-time use term, we could > copy the form of the "predicate-static" term and use "nonblocking-static". > Other ideas? Yes, nonblocking-static is probably where we will end up. ****************************************************************