To: J3 J3/22-154r3 From: Tom Clune & subgroup generics Subject: Generics formal specs: semantics of instantiating templates Date: 2022-July-20 References: 22-120r5, 22-151r1 1. Introduction =============== This paper is intended to establish the formal specs of generic programming with respect to the semantics of instantiating templates. 2. Formal specs =============== A1. The INSTANTIATE statement names a template and provides a list of actual template parameters corresponding to the dummy parameters of the referenced template. A2. The INSTANTIATE statement identifies a template instance, that is similar to a module that contains concrete instances of the entities defined in the referenced template. B1. The INSTANTIATE statement can only appear in the specification section of a program unit. B2. The INSTANTIATE statement cannot appear before any of the following statements in the same program unit: - USE statements - IMPLICIT statements B3. References to instance entities accessed by an INSTANTIATE statement shall appear after that INSTANTIATE statement, except for PUBLIC/PRIVATE statements. C1. The INSTANTIATE statement provides an optional ONLY clause that enables fine-grained access to individual template instance entities. C2. The INSTANTIATE statement provides rename capabilities analogous to those of the USE statement for modules. 2.1 Association of actual template parameters in INSTANTIATE ------------------------------------------------------------ D1. The corresponding actual template parameter for a dummy type template parameter shall be a type-spec with constant specification expressions. Example: TEMPLATE tmpl(T) TYPE T; END TYPE ... END TEMPLATE tmpl TYPE :: my_pdt(len, n) INTEGER, LEN :: len INTEGER, KIND :: n INTEGER :: B(len) REAL, RANK(n), ALLOCATABLE :: A INTEGER :: data END TYPE INSTANTIATE tmpl(REAL) INSTANTIATE tmpl(INTEGER(KIND=INT64)) INSTANTIATE tmpl(my_pdt(len=5, n=3)) ! ok INSTANTIATE tmpl(my_pdt(len=:, n=3)) ! illegal; no deferred D2. The corresponding actual template parameter for a dummy value template parameter shall be a constant expression of the same type, kind, and rank. If the shape of a dummy template parameter is explicit then the corresponding actual parameter shall have the same shape. If the shape of a dummy template parameter is assumed, then the corresponding actual parameter shall have the same rank. For an assumed rank dummy template parameter the corresponding actual parameter can have any rank or shape. NOTE: To avoid complexities about what "same" means for user-defined types as well as round-off issues with expressions involving numeric types, subgroup has decided to restrict value dummy template parameters to be logical, integer, or assumed-len strings. These cover all of the generics use cases, but the original requirements paper then generalized to any const expression. A revision to the requirements paper will be submitted. Example using notional syntax: TEMPLATE tmpl1(T, flag, n, pet_type) TYPE T; END TYPE LOGICAL, PARAMETER :: flag INTEGER, PARAMETER :: n CHARACTER(LEN=*), PARAMETER :: pet_type TYPE(T), RANK(n), ALLOCATABLE :: data END TEMPLATE tmpl1 ! Legal instantiations INSTANTIATE tmpl1(REAL, .true., 0, 'cat') INSTANTIATE tmpl1(INTEGER, .false., 1, 'doggy') ! The following are illegal. INSTANTIATE tmpl1(REAL, 1, 1, 'cat') ! wrong type expr for 'flag' INSTANTIATE tmpl2(REAL, .true., 0, & [character(len=5)::'cat','doggy']) ! wrong rank for pet_type Another example using assumed rank: TEMPLATE tmpl2(C) INTEGER, PARAMETER :: C(..) CONTAINS SUBROUTINE ACCUM(x y) INTEGER, INTENT(IN), RANK(RANK(C)) :: x INTEGER, INTENT(OUT), RANK(RANK(C)) :: y y = x + C END SUBROUTINE END TEMPLATE tmpl2 D3. A generic interface name may be used as an actual procedure template parameter at instantiation provided one of its specific procedures matches the required interface of the corresponding dummy procedure template parameter. The matching specific procedure is then treated as the effective actual procedure template parameter. Note: Procedure dummy template parameters are not permitted to have an implicit interface. Thus, there can never be any ambiguity in the generic resolution in this context. Example: TEMPLATE mytmpl(T, F) TYPE :: T; END TYPE INTERFACE FUNCTION F(x) TYPE(T), INTENT(IN) :: x TYPE(T) :: F END FUNCTION END INTERFACE ... END TEMPLATE mytmpl ... INSTANTIATE mytmpl(REAL, sin) INSTANTIATE mytmpl(DOUBLE PRECISION, sin) D4. An operator may be used as an actual template parameter at instantiation provided one of its specific procedures matches the required interface of the corresponding dummy procedure template parameter. The matching specific procedure is then treated as the effective actual procedure template parameter. NOTE: This approach is arguably a bit klunky but it sidesteps thorny issues related to how dummy operator parameters could be declared, and allows template authors to define useful operators inside the template. Example: TEMPLATE mytmpl(T, F) TYPE :: T; END TYPE INTERFACE FUNCTION F(x, y) TYPE(T), INTENT(IN) :: x, y TYPE(T) :: F END FUNCTION END INTERFACE ... END TEMPLATE mytmpl ... INSTANTIATE mytmpl(REAL, +) INSTANTIATE mytmpl(INTEGER, *) 2.2 Identical instantiations ---------------------------- E1. By default, instantiations of a given template with the same actual template parameters identify the same template instance. E2. The INSTANTIATE statement shall provide a mechanism that overrides the default behavior for identification of the template instance. When this mechanism is applied, an INSTANTIATE statement shall identify a template instance that is distinct from all other template instances. Example using notional syntax TEMPLATE wrapper_tmpl(T) type :: T; end type type :: wrapper type(T) :: wrapped end type END TEMPLATE INSTANTIATE wrapper_tmpl(real), real_w => wrapper INSTANTIATE wrapper_tmpl(real), other_w => wrapper INSTANTIATE, UNIQUE :: wrapper_tmpl(real), w1 => wrapper INSTANTIATE, UNIQUE :: wrapper_tmpl(real), w2 => wrapper ! Types real_w and other_w are the same type. ! Type w1 is a different type than all of real_w, other_w and w2 ! Type w2 is a different type than all of real_w, other_w and w1 E2. Two value actual template parameters are the same if: - both are logical and are equivalent. - both are integer and equal. - both are character constants of the same length and equal. E3. Two corresponding type-spec actual template parameters are the same if they have the same type and have the same kind and length-type parameters. Note that assumed length-type parameters are not permitted for type-spec actual template parameters. E4. Two corresponding procedure actual template parameters are the same if they resolve to the same specific procedure within the template. Example: INTERFACE A MODULE PROCEDURE F1 ! operates on MY_T MODULE PROCEDURE F2 ! operates on MY_U END INTERFACE A INTERFACE B MODULE PROCEDURE F1 ! operates on MY_T MODULE PROCEDURE F3 ! operates on MY_U END INTERFACE B TEMPLATE TMPL(T, F) TYPE T; END TYPE INTERFACE SUBROUTINE f(x) TYPE(T), INTENT(INOUT) :: x END SUBROUTINE f(x) END INTERFACE END TEMPLATE INSTANTIATE TMPL(MY_T, A) ! Resolves to F1 INSTANTIATE TMPL(MY_T, A) ! Resolves to F1 ==> same INSTANTIATE TMPL(MY_T, A) ! Resolves to F1 INSTANTIATE TMPL(MY_T, B) ! Resolves to F1 ==> same INSTANTIATE TMPL(MY_U, A) ! Resolves to F2 INSTANTIATE TMPL(MY_U, B) ! Resolves to F3 ==> different ===END===