To: J3 J3/23-223r1 From: John Reid & Hidetoshi Iwashita & Malcolm Cohen Subject: Formal requirements for generic procedures Date: 2023-October-21 Reference: N2217 1. Introduction =============== At its meeting Jun 12-16, 2023, WG5 decided to approve generic procedures as described in N2217 for Fortran 202Y. Use cases for this are set out in N2217. Here we present formal requirements, some formal specifications, and some illustrative syntax. 2. Formal requirements ====================== a. There shall be a mechanism for defining a generic procedure, with a single procedure body rather than a set of specific procedures. b. Such a generic procedure will have a generic name, but no specific name. c. There shall be a mechanism for defining a generic procedure with a generic identifier that is an operator name, assignment, or input/output. d. A generic procedure shall have one or more "generic" dummy arguments; a generic dummy argument is one that might have more than one value for a kind type parameter, more than one rank, or (assuming feasibility) more than one type. NOTE: The proposed template facility has extensive features for handling different types; this is not meant to duplicate those. The motivating examples for different type are: (ex1) algorithms which work the same for real and complex; (ex2) algorithms which work the same for an intrinsic type such as real, and also for a user-defined type which provides a variation on such an intrinsic type. e. As implied by the above, such a generic procedure implicitly defines an anonymous set of specific procedures, one for every combination of type, kind type parameter value, and rank. We will call each such combination a "generic combination". f. A local variable of a generic procedure can have the same type, type parameters, and rank, as a generic dummy argument. Function result variables similarly. g. There shall be a construct for ad-hoc specialization of executable code for the type and/or kind type parameter values of a dummy argument that is generic in type and/or kind. NOTE: We already have such a construct for runtime polymorphism, but this requirement means compile-time polymorphism. h. There shall be a construct for ad-hoc specialization of executable code for the rank of a dummy argument that is generic in rank. NOTE: We already have such a construct for runtime rank variability, but this requirement is for compile-time rank variability. i. If possible, this generic procedure facility should be available for generic type-bound procedure definition. NOTE: This should be straightforward, except perhaps for coming up with convincing syntax. j. If possible, this generic procedure facility should be available within a template. k. If possible, this generic procedure facility should be available as a separate module subprogram, i.e. using a submodule. NOTE: All of the "if possible" requirements depend on feasibility in the language design, standard wording, and implementation. If any of those aspects are difficult, they should be reconsidered. 3. Formal specifications ======================== Generic procedure definition and identification: s01. A "generic procedure" shall be defined by a "generic subprogram". s02. A generic subprogram shall be a module subprogram, and shall not have multiple entry points (i.e. no ENTRY statement). NOTE: Although N2217 envisaged generic external subprograms, external subprograms need to have global names to be referenced. That would be undesirable - putting them in a module is easier to understand and safer to use. NOTE: In principle, this includes the possibility of being a separate module subprogram defined in a submodule, in which case there would be a generic module procedure interface in the ancestor module. NOTE: This specification may be revisited if sufficiently compelling reasons for needing generic external subprograms are found, and that are not satisfied by other means such as submodules. s03. A generic subprogram can have internal subprograms. s04. Every generic subprogram shall have a generic name. s05. The name of a generic procedure/subprogram shall be able to be added to the generic set of a generic identifier that is not a name, i.e. operator, assignment, input/output. s06. There is no specification regarding the ability or inability (as now), for adding a generic name that is a traditional generic set to the generic set of another generic identifier. Consistency may suggest doing this. Within a generic subprogram: s07. A generic procedure shall have at least one generic dummy argument. s08. There shall be a syntax that specifies all valid kinds of an intrinsic type for a generic dummy argument. The dummy argument is a generic dummy argument even if a compiler supports only one kind for the type. s09. There shall be a syntax that specifies all valid ranks. s10. There shall be a syntax that specifies a set of kind type parameter values (as constant expressions). This syntax shall be usable for parameterized derived types as well as for intrinsic types. The dummy argument is still generic even if only evaluates to one kind (assuming the syntax is different from normal non-generic kind specification). s11. There should be a hopefully-similar syntax for a list of ranks to be generic over. s12. Assuming that generic-by-type is feasible and we do it, syntax is needed to supply a list of type-specs, which may be intrinsic types or user-defined types. s13. A rank-generic dummy argument shall be a pointer, allocatable, or assumed-shape. It may have the CONTIGUOUS attribute, even if rank zero is included in the set of ranks. s14. A generic dummy argument may be polymorphic, if and only if every type over which it is generic is an extensible type. None of these types may be an extension of another. s14. The declarations within a generic subprogram shall be consistent with every generic combination. s16. The executable code within a generic subprogram, other than that within an ad-hoc specialization construct, shall be consistent with every generic combination. s17. Not only local variables (and the function result) of a generic subprogram may be declared to have the same attributes as a generic dummy argument, but also local variables (and function results) of nested scoping units viz. BLOCK constructs and internal subprograms. s18. The executable code within a block of an ad-hoc specialization need only be consistent with the specified generic combination. NOTE: This is exactly how our existing runtime ad-hoc polymorphism constructs work. s19. Ad-hoc specialization shall be performed at compile time, that is, there will be no trace of the non-chosen specializations in the generated anonymous specific. NOTE: This is aspirational, as there is no way at present to express it normatively. 4. Illustrative syntax ====================== i01. A generic (module) subprogram shall have the GENERIC keyword in its procedure heading (the SUBROUTINE or FUNCTION statement). i02. A generic procedure name may be added to the generic set of any other generic name by specifying it as a "procedure" in an interface block, using the PROCEDURE statement, or by listing it as a procedure-name in a GENERIC statement. i03. Genericity over all valid kind type parameters of an intrinsic type is specified by KIND=*. Similarly, genericity over all valid ranks is specified by RANK(*). i04. Genericity over a set of kind type parameter values is specified by KIND=array-expr, e.g. KIND=[int32,int64]. Similarly, genericity over a set of valid ranks is specified by RANK(array-expr), e.g. RANK([1,2,3]). In both cases, duplicated values are not allowed. i05. Genericity over a set of types is specified by TYPE(type-spec-list), e.g. TYPE(INTEGER(int64),REAL(real64),COMPLEX). i06. For non-polymorphic dummy arguments generic in type, a SELECT TYPE construct can be used; in this case no "CLASS IS(...)" block will be allowed. Maybe "CLASS DEFAULT" should be "TYPE DEFAULT"? i07. For polymorphic dummy arguments, care needs to be taken in the design to establish which blocks are resolved at compile time, and which at runtime, but given no generic type will be an extension of another, this should be straightforward. i08. For dummy arguments generic in rank, the SELECT RANK construct can be used to select the rank. For more illustrative syntax, refer to N2217. 5. Example ========== Module example1 Interface Operator(.myop.) Procedure s ! All of the specific procedures of s. End Interface Contains Generic Subroutine s(a,b) Type(Real,Complex), Intent(InOut), Rank(*) :: a, b Type(Typeof(b)), Rank(Rank(b)) :: temp ... Select Type (b) Type Is (Real) temp = temp * (1-b) Type Is (Complex) ! Just this once, we want the conjugate. temp = temp * (1-Conjg(b)) End Select ... End Subroutine End Module ===END===