To: J3 J3/22-120 From: Tom Clune & generics subgroup Subject: Generics formal requirements Date: 2022-February-14 Reference: 21-187, 21-144r4 1. Introduction =============== At meeting 224, generics subgroup introduced a use cases paper that was sufficient to drive solutions that would accommodate a broader set of use cases that were endorsed by subgroup. Here we present the formal requirements that have been derived from these use cases. 2. Formal requirements ====================== Progress on developing a draft requirements paper has been much slower than was anticipated at the last meeting. The following is a very rough list of formal requirements that have general support by subgroup: A. Named templates shall be provided. Notionally templates will be much like modules -- containing specification and implementation sections. But these will be distinct from modules. A suggestive example is as follows TEMPLATE TMPL(U) TYPE :: U END TYPE CONTAINS PURE FUNCTION GET_ITH(arr, i) result(ith) TYPE(U) :: ith TYPE(U), INTENT(IN) :: arr(:) INTEGER, INTENT(IN) :: i ith = arr(i) END FUNCTION END TEMPLATE TMPL Rationale 1: Having a separate construct will allow templates to be defined _and_ instantiated within the same scope. Rationale 2: This approach sidesteps thorny issues with submodules that would be introduced with a parameterized module approach. B. Named restrictions shall be provided. Notionally, a "restriction" is a construct which specifies operations that must be supported for legal instantiations of a template. E.g., we may require that types T and U can be added to produce objects of type V. A very hand-wavy syntax could be something like: RESTRICTION :: BINARYOP(+,T,U,V) TYPE T; END TYPE TYPE U; END TYPE TYPE V; END TYPE T + U => V END RESTRICTION C1. A template shall have zero or more dummy template parameters. Note: A zero parameter template would be very similar to a plain module. But the additional scoping might make this useful? C2. A template can define any of the following entities: - derived type - variable - procedure - interface D. A template dummy parameter must be one of the following: - type name - value - procedure - operator A suggestive example involving all categories of dummy template parameters: TEMPLATE TMPL2(T,C,sub,+) TYPE :: T END TYPE INTEGER :: C INTERFACE SUBROUTINE sub(x) TYPE(T), INTENT(INOUT) :: x END SUBROTUINE sub END INTERFACE END TEMPLATE Note: Operators may not require explicit declaration as both intrinsic and user-defined operators are self-evident by their syntax. E. A template shall be instantiated by specifying an actual parameter for each dummy template parameter. E1. A type-spec must be provided for a type name dummy template parameter. E2. A const-expr must be provided for a value dummy template parameter. E3. A procedure or a generic-spec must be provided for a procedure dummy template parameter E4. An operator must be provided for an operator dummy template parameter. Notional syntax: INSTANTIATE TMPL(INTEGER(KIND=INT32)) ... INTEGER(KIND=INT32) :: I, ARRAY(10) ... I = GET_ITH(ARRAY, 3) Note 1: A generic-spec may be passed as a dummy argument, because resolution can be done during instantiation. Note 2: A generic operator may be passed as a dummy argument, because resolution can be done during instantiation. Rationale: Client code often does not have access to specific names for procedures and operators. And the ability to use generic entities is too important too disallow in this context. In particular intrinsic operators are extremely important. F. Multiple instantiations of a given template with identical actual template parameters define the same entities. Note that this is somewhat contrary to the existing situation where two otherwise identical derived types define distinct types. G. A named restriction shall have a set of zero or more dummy restriction parameters. NOTE: The zero-argument case here is not useful. Possibly this should become "one or more". H. A dummy restriction parameter shall be one of the same categories as for dummy template parameters. (type, value, procedure, operator) Note: "value" probably does not make sense in this context. But possibly does no harm? I. A named restrictions shall specify a set of "relations". J. A restriction relation specifies one of the following: - an operator and the types of its operands and result - a procedure and the types of its arguments; in the case of a function it must also specify the type of the result K. A template may impose zero or more "requires". A suggestive example with 2 REQUIRES RESTRICTION :: MAGMA(U, OPERATOR(+)) TYPE :: U END TYPE :: U U + U => U END RESTRICTION TEMPLATE :: TMPL2(U, V) REQUIRES MAGMA(U, OPERATOR(+)) REQUIRES MAGMA(V, OPERATOR(*)) ... CONTAINS SUBROUTINE DO_SOMETHING(x, y) TYPE(U) :: x TYPE(V) :: y x = x + x*x ! legal y = y + y*y ! legal x = x + y ! illegal - no supporting requirement x = 2*x ! illegal integer multiply not in requirements END SUBROUTINE DO_SOMETHING END TEMPLATE TMPL2 Rationale: Restrictions are intended to be reusable in multiple contexts. We expect that restrictions will often be defined external to templates. L. A template may not use any procedures or operators except those that have been specified in a REQUIRES statement. Rationale: This is the notion of a "strong concept" which allows template developers to ensure that a template does not have any implicit requirements that might not be detected for some unanticipated template parameters. N. A template instantiation must satisfy all imposed requirements Note: This is the notion of a "weak concept" which requires that invalid dummy template parameters be diagnosed as such rather than being diagnosed as syntax or linkage errors in the expanded code. 3. Commentary ============= A. Subgroup has decided to disallow type-bound operators/procedures as template parameters at this time. This does not lead to any loss of functionality, as users can readily wrap such entities as non type-bound operators/procedures if necessary. 4. Unresolved technical issues ============================== UTI-1: Can operator relations in a restriction specify rank? E.g., INTERFACE OPERATOR(+) FUNCTION plus(x, y) result(z) TYPE(T), INTENT(IN) :: x, y(3) TYPE(T) :: Z(3) END FUNCTION END INTERFACE How would we express this in a relation? UTI-2: Do procedure relations in a restriction need to specify argument INTENT? Our suggestive syntax does not support this. INTENT could be implicit for operators, as it must be INTENT(IN) for these. ===END===