To: J3 J3/22-124r2 From: Tom Clune & generics subgroup Subject: Generics formal specs Date: 2022-February-28 Reference: 22-120r1, 21-144r4 1. Introduction =============== Paper 21-144r4 provided use cases for Fortran generics feature, and paper 22-120r1 provided formal requirements. This paper provides formal specifications. 2. Formal specs =============== A. TEMPLATE is a named scoping unit. B1. A TEMPLATE definition has the following elements: - TEMPLATE name - list of TEMPLATE dummy parameters - specification section (possibly empty) - optional procedure section begining with a CONTAINS statement Aside: I.e., this looks very much like a module in most respects. Suggestive syntax: TEMPLATE T([param1[, param2[, ...]]]) ! specification section CONTAINS ! procedure definitions END TEMPLATE T B2. The permitted order of statements in a TEMPLATE is the same as that for modules. B3. A TEMPLATE dummy parameter declaration must appear before any reference to that parameter and must appear after any USE, IMPORT, and IMPLICIT NONE statements in the TEMPLATE. Suggestive syntax: TEMPLATE TMPL(T, FLAG, sub) TYPE :: T; END TYPE ! dummy type parameter LOGICAL :: FLAG ! dummy constant (logical) parameter INTERFACE SUBROUTINE sub(x, y) ! dummy subroutine parameter TYPE(T), INTENT(IN) :: x TYPE(T), INTENT(OUT) :: y END SUBROUTINE END INTERFACE B4. A TEMPLATE dummy parameter declaration that is a type may not contain any components, type-bound procedures, nor have any KIND or LEN type parameters. NOTE: This restriction is on the declaration of the _dummy_ parameter. The TEMPLATE _actual_ parameter can, of course, have components, type-bound procedures, and KIND/LEN type parameters, but these are not accessible within the template. C. A TEMPLATE can be defined in the specification section of: - PROGRAM - MODULE - SUBMODULE - procedure (including internal subprogram) - BLOCK construct - another TEMPLATE Aside: Basically any place that a TYPE can be defined. Straw Vote 1: Should a TEMPLATE be permitted to contain an internal TEMPLATE definition? YES-NO-UNDECIDED D. A TEMPLATE may only be referenced by host association or use association. E1. There shall be a nonexecutable specification construct INSTANTIATE for instantiating templates by providing the means by which a scoping unit defines named entities provided by a TEMPLATE. E2. An INSTANTIATE statement must provide the name of an accessible TEMPLATE and a list of TEMPLATE actual parameters corresponding to the TEMPLATE dummy parameters of the specified TEMPLATE. Suggestive syntax: TEMPLATE MY_TMPL(U, V, S) ... END TEMPLATE MY_TMPL ... ! Host association ... INSTANTIATE MY_TMPL(MY_U, MY_V, MY_SUBR) E4. The INSTANTIATE statement can appear only in the specification section in any of: - PROGRAM - MODULE - SUBMODULE - another TEMPLATE - procedure - BLOCK construct Aside: I.e., any place one could declare a variable. E5. A TEMPLATE must not INSTANTIATE itself (directly or indirectly). E6. The INSTANTIATE feature must allow functionality analogous to the ONLY and rename clauses of module USE statements to enable disambiguation of provided entities. Suggestive syntax: USE my_module, ONLY: T ! T is a TEMPLATE ... ! The following statement provides access to the entity S ! defined inside TEMPLATE T, but using the name S_1 INSTANTIATE :: T(param1, param2), ONLY: S_1 => S F1. A RESTRICTION is a specifier that establishes a set of relations among its dummy parameters. NOTE: This feature is intended to allow reuse of relations among multiple templates by providing descriptive names which can be helpful to the reader and avoids repetitious interface blocks in each scope. F3. A relation is an interface body defined in a RESTRICTION. F4. A RESTRICTION definition has the following elements: - RESTRICTION name - nonempty list of RESTRICTION dummy parameters - specification section that consists of * declaration of RESTRICTION dummy parameters * interface blocks that define relations among the dummy parameters * REQUIRES statements (see below) Rationale: Allowing REQUIRES within a RESTRICTION provides the ability to assemble complex RESTRICTIONS and reduces duplication. Aside: This looks a bit like a TEMPLATE in terms of its parameters, but is much narrower in terms of what is allowed in the contents. Suggestive syntax: RESTRICTION C(T, U, F1, F2) TYPE :: T; END TYPE TYPE :: U; END TYPE INTERFACE ! Conceptually: F1(T) => T ! Conceptually: F2(T,U) => U END INTERFACE END RESTRICTION C F5. Declarations of a RESTRICTION dummy parameter must precede any reference to that parameter. G. A RESTRICTION can be defined in the specification section of: - PROGRAM - MODULE - SUBMODULE - TEMPLATE - procedure (including internal subprogram) - BLOCK construct H. A RESTRICTION can only be referenced by host association or use association. Suggestive syntax: RESTRICTION R(...) ... END RESTRICTION TEMPLATE T(...) REQUIRES R(...) ! host association END TEMPLATE I. Each relation in a RESTRICTION establishes the interface of a single SUBROUTINE, FUNCTION, or OPERATOR corresponding to a RESTRICTION dummy parameter. NOTE: Further generalization is possible and possibly desirable, but the above satisfies the current use cases driving this design. J1. There shall be a nonexecutable specification statement REQUIRES which is used to enforce a RESTRICTION during the instantiation of a TEMPLATE as well as to limit permitted operations used within the template. See UTI-8 J2. A REQUIRES statement must provide the name of an accessible named RESTRICTION and a list of RESTRICTION actual parameters corresponding to the RESTRICTION dummy parameters. Suggestive syntax: RESTRICTION MAGMA(T, binaryop) TYPE :: T; END TYPE INTERFACE PURE FUNCTION binaryop(x, y) RESULT(z) TYPE(T) :: z TYPE(T), INTENT(IN) :: x, y END FUNCTION END INTERFACE END RESTRICTION MAGMA TEMPLATE MY_TMPL2(U, V, plus, times) ... REQUIRES MAGMA(U, plus) ! U = plus(u,u) REQUIRES MAGMA(V, times) ! V = times(v,v) ... END TEMPLATE J3. A REQUIRES statement may be placed only in the specification section of a TEMPLATE. See UTI-8 L. A TEMPLATE may be instantiated only if all of the relations established by the REQUIRES statements hold for the TEMPLATE actual parameters. This is referred to as "weak" constraints/concepts. M1. A TEMPLATE may only reference a dummy parameter that is a SUBROUTINE, FUNCTION, or OPERATOR if the relevant interface is defined in a REQUIRES statement within the TEMPLATE. This is referred to as "strong" constraints/concepts. A example with suggestive syntax: MODULE M1 ... public :: T1, F RESTRICTION MAGMA(T, F) INTERFACE FUNCTION F(x,y) RESULT(z) TYPE(T), INTENT(IN) :: x, y TYPE(T) :: z END FUNCTION END INTERFACE END RESTRICTION TEMPLATE T1(T, G1, G2) REQUIRES MAGMA(T, G1) CONTAINS SUBROUTINE FOO(x,y) TYPE(T), INTENT(IN) :: x TYPE(T), INTENT(OUT) :: y y = G1(x,x) ! OK - covered by REQUIRES statement END SUBROUTINE SUBROUTINE BAR(x,y) TYPE(T), INTENT(IN) :: x TYPE(T), INTENT(OUT) :: y y = G2(x,x) ! ILLEGAL - not covered by REQUIRES statement END SUBROUTINE END TEMPLATE END MODULE M1 Straw vote: May a TEMPLATE definition use intrinsic _assignment_ for TEMPLATE dummy parameters without a corresponding RESTRICTION? YES-NO-undecided PRO: This is a common situation and virtually all Fortran types satisfy this property. Adding the appropriate RESTRICTION will be a bit tedious and may confuse some developers. CONS: This creates a small hole in the intent of "strong" constraints. M2. A TEMPLATE dummy parameter that is a SUBROUTINE, FUNCTION or OPERATOR must either appear in exactly one REQUIRES statement or have an identical interface in each associated RESTRICTION. M3. A RESTRICTION dummy parameter that is a SUBROUTINE, FUNCTION or OPERATOR must be given a single interface. E.g., the following pseudocode is illegal because F is given 2 different interfaces. RESTRICTION R(T, U, F) TYPE :: T; END TYPE TYPE :: U; END TYPE INTERFACE FUNCTION F(x,y) RESULT(z) TYPE(T) :: x, y, z END FUNCTION FUNCTION F(x,y) RESULT(z) TYPE(U) :: x, y, z END FUNCTION END INTERFACE END RESTRICTION NOTE: This appears to be already covered by existing rules in Clause 19.3.1p3 (22-007). M4. No variable of a type corresponding to a TEMPLATE dummy parameter may be used as an actual argument to a SUBROUTINE, FUNCTION, or OPERATOR unless the corresponding dummy argument is declared with the same TEMPLATE dummy parameter type. M5. A TEMPLATE dummy parameter which is a type name is indistinguishable from any other type in a procedure characteristic for the purposes of generic interface definition. For example the following is illegal: TEMPLATE TMPL(T, U) PUBLIC :: BAR INTERFACE BAR MODULE SUBROUTINE BAR_T(x) TYPE(T) :: x END SUBROUTINE MODULE SUBROUTINE BAR_i(x)! Ambiguous: what if T is integer? TYPE(integer) :: x END SUBROUTINE MODULE SUBROUTINE BAR_U(x)! Ambiguous: what if U is same as T? TYPE(U) :: x END SUBROUTINE END INTERFACE END TEMPLATE M6. A TEMPLATE dummy parameter which is a type name may not be extended within the template. E.g., TEMPLATE TMPL(T) TYPE :: T; END T TYPE, EXTENDS(T) :: CHILD ! Illegal END TYPE END TEMPLATE 3. Unresolved technical issues ============================== UTI-8: Where can a REQUIRES statement go? Something analogous might be useful in terms of expressing programmers intent in satisfying a REQUIREMENT in non TEMPLATE contexts; possibly with a different syntax term for clarity. ===END===