To: J3 J3/23-103r1 From: Tom Clune Subject: Generics formal requirements Date: 2023-February-22 Reference: 22-120r5, 22-120r5 1. Introduction =============== This paper revises paper 22-120r5, Generics formal requirements, to reflect improvements based upon further work on the corresponding syntax paper. The changes are generally minor with a few now-disallowed items being removed, and updates to the latest proposed syntax in examples. 2. Formal requirements ====================== A. Named templates shall be provided. A TEMPLATE is a parameterized scoping unit which can contain variables, type definitions, procedure definitions, etc. Templates can be 'instantiated' to yield concrete (i.e., non-parameterized) instances of entities defined within the template. Aside: The TEMPLATE approach for providing generic programming facilities is similar to previously proposed PARAMETERIZED MODULES (PM) (paper 03-264). The key differences are: A template can be declared within a program unit and then instantiated within that same program unit. (Not within itself!) This is _not_ a formal requirement, but it can be useful to use locally defined specialized templates within a program unit. An example of a simple TEMPLATE with suggestive syntax is given below. The TEMPLATE name is "TMPL" and has one (dummy) TEMPLATE parameter "U" which is a type. The TEMPLATE provides a single function "GET_ITH" whose first argument is of type U. TEMPLATE TMPL(U) TYPE, DEFERRED :: U 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 B. Named requirements shall be provided. A REQUIREMENT is a parameterized construct that provides a mechanism for expressing necessary relationships among a set of TEMPLATE dummy parameters. Such relationships serve as a filter on allowed actual parameters to a TEMPLATE (see "weak concepts" below), and also to facilitate verification that a template will produce valid code for sets of actual parameters that satisfy the requirement. (See "strong concepts" below.) Notionally, a REQUIREMENT is a construct which specifies the procedures that must be supported for legal instantiations of a TEMPLATE. E.g., one may require that types T and U can be added to produce objects of type V. Suggestive syntax for this is: REQUIREMENT :: BINARYOP(F,T,U,V) TYPE, DEFERRED :: T TYPE, DEFERRED :: U TYPE, DEFERRED :: V FUNCTION F(x,y) RESULT(z) TYPE(T), INTENT(IN) :: x TYPE(U), INTENT(IN) :: y TYPE(V) :: z END FUNCTION END REQUIREMENT Aside: A REQUIREMENT is somewhat similar to an abstract interface in that it contains a group of otherwise unrelated procedure interfaces, but different in that (1) it has a name, which facilitates reuse in multiple contexts, and (2) is parameterized. C1. A template shall have zero or more template dummy parameters. C2. A template can define any of the following entities: - derived type - procedure - interface - another template - constants - enumeration types and their enumerators D. A template dummy parameter must be one of the following: - type - value - procedure A suggestive example involving all categories of template dummy parameters: TEMPLATE TMPL2(T,C,sub) TYPE, DEFERRED :: T INTEGER, CONSTANT :: C INTERFACE SUBROUTINE sub(x) IMPORT T TYPE(T), INTENT(INOUT) :: x END SUBROUTINE sub END INTERFACE END TEMPLATE E. The INSTANTIATE statement shall be provided. The INSTANTIATE statement specifies the name of a TEMPLATE and a list of TEMPLATE actual parameters corresponding to the TEMPLATE's dummy parameters. E1. A type-spec must be provided for a type name template dummy parameter. E2. A const-expr (of the correct type) must be provided for a value template dummy parameter. E3. A procedure or a generic-spec must be provided for a procedure template dummy parameter Suggestive syntax: INSTANTIATE TMPL(INTEGER(KIND=INT32)) ... INTEGER(KIND=INT32) :: I, ARRAY(10) ... I = GET_ITH(ARRAY, 3) E4. A generic-spec may be passed as an actual template parameter corresponding to a dummy procedure parameter, because generic resolution can be done during instantiation. Rationale: Client code often does not have access to specific names for procedures. And the ability to use generic entities is far too valuable to disallow in this context. F. Multiple instantiations of a given TEMPLATE with identical template actual parameters define the same instance within a program. Consequences: 1. A derived type defined in a template is the _same_ type across all instantiations that have the identical template actual parameters. 2. An enumeration and its associated enumerators are the same across all instantiations that have the identical template actual parameters. Multiple instantiations of a given template with _any_ different actual parameters do _not_ define the same instance. In particular any derived types, enumerators etc. defined in these instances are distinct. NOTE: While BIND(C) use is not prohibited within a TEMPLATE, it may be problematic as it can associate distinct entities with the same global identifier. G. A named REQUIREMENT shall have a set of zero or more dummy requirement parameters. NOTE: The zero-parameter case here is not useful. Possibly this should become "one or more parameters". H. A REQUIREMENT dummy parameter shall be one of the same categories as for TEMPLATE dummy parameters. (type, constant, procedure) I. A named REQUIREMENT shall specify a set of interfaces that hold among its dummy parameters: TKR of procedure arguments and function results. K. The REQUIRES statement shall be provided. A REQUIRES statement specifies the name of a REQUIREMENT and a set of actual parameters corresponding to the REQUIREMENT parameters. A TEMPLATE uses REQUIRES statements to indicate relations among its own parameters that are necessary for the TEMPLATE to be valid. Legal instantiations must provide actual parameters that satisfy all of a template's REQUIRES statements ("weak concepts") and also may not use any other procedures involving the template parameters that are types ("strong concepts"). Note: A more precise statement of strong concepts will be provided in the specs paper to come. Also, weak and strong concepts are called out as separate requirements below. A suggestive example of a template with 2 REQUIRES: REQUIREMENT :: MAGMA(U, F) TYPE, DEFERRED :: U FUNCTION F(x,y) RESULT(z) TYPE(T), INTENT(IN) :: x, y TYPE(T) :: Z END FUNCTION END REQUIREMENT TEMPLATE :: TMPL2(U, V, ADD, TIMES) REQUIRES MAGMA(U, ADD) ! implements U+U -> U REQUIRES MAGMA(V, TIMES) ! implements U*U -> U ... 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 L. A TEMPLATE instantiation must satisfy all imposed requirements. Note: This is the notion of a "weak concept" which requires that invalid template dummy parameters be diagnosed as such rather than being diagnosed as syntax or linkage errors in the instantiated code. M. A TEMPLATE may not reference any procedures whose arguments and/or function result variable are of a type that is a dummy type parameter except for those whose interfaces 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. Declarations of dummy template parameters that are types shall not specify: - type parameters - components - a type-bound procedure part ===END===