To: J3 J3/24-125r1 From: generics Subject: Formal syntax (1 of 3): deferred arguments Date: 2024-June-17 Reference: This paper is the first of three that comprise the formal syntax for generic programming features in Fortran, aka templates. 1. Introduction =============== This paper defines the formal syntax for deferred arguments. Paper 2 covers the syntax related to the TEMPLATE construct and INSTANTIATION statement, while paper 3 provides the syntax for the REQUIREMENT construct and the REQUIRES statement. Deferred arguments are template "dummy" arguments that are given their "values" when the template is instantiated. Deferred arguments can be constants, procedures, or types. Section 2 provides a non-pedagogical example that exercises most of the proposed syntax. Section 3 defines the formal syntax for deferred entities. 2. Example ========== MODULE A REQUIREMENT R{U,G} TYPE, DEFERRED :: U INTERFACE FUNCTION G(x, i) RESULT(y) TYPE(U) :: y TYPE(U), INTENT(IN) :: x INTEGER, INTENT(IN) :: i END FUNCTION G END INTERFACE END REQUIREMENT R TEMPLATE B{T,F,C} REQUIRES R{T,F} ! provides interface for deferred F TYPE, DEFERRED :: T ! redundant decl of deferred type T INTEGER, CONSTANT :: C(..) ! deferred rank constant CONTAINS SUBROUTINE SUB1(x) TYPE(T), INTENT(INOUT) :: x x = F(x, SUM(C)) END SUBROUTINE SUB1 SUBROUTINE SUB2(x) TYPE(T), INTENT(INOUT) :: x x = F(x, MAXVAL(C)) END SUBROUTINE SUB2 END TEMPLATE B CONTAINS SUBROUTINE SUB3{V,D}(x) TYPE, DEFERRED :: V INTEGER, CONSTANT :: D TYPE(V), INTENT(INOUT) :: x(D) x(D) = x(1) END SUBROUTINE END MODULE A MODULE C USE MODULE A INSTANTIATE B{REAL, OPERATOR(*), [3,4]}, ONLY: & & tot_sub1 => sub1 INSTANTIATE B{REAL, OPERATOR(+), [3,4]}, ONLY: & ! different instance & max_sub2 => sub2 CONTAINS SUBROUTINE DO_SOMETHING(x) REAL, INTENT(INOUT) :: x INTEGER :: y(3) x = 2. CALL tot_sub1(x) PRINT*,'TOT: ', x ! expect 2. * (3+4) = 14. x = 3. CALL max_sub2(x) PRINT*,'MAX: ', x ! expect 3. + max(3,4) = 7. y(1) = 4 call sub3{INTEGER, 3}(y) PRINT*, y(3) ! expect 4 END SUBROUTINE DO_SOMETHING END MODULE C 3. Syntax for Deferred entities =============================== A deferred argument is an entity that takes some of its characteristics from its ultimate instantiation argument. A deferred argument can be a constant, type, or procedure and can appear in a REQUIREMENT construct, TEMPLATE construct, or standalone template procedure (STP). Association with instantiation arguments occurs in the REQUIRES and INSTANTIATE statements. A deferred constant is a deferred argument that can appear in constant expressions within a REQUIREMENT construct, TEMPLATE construct, or STP. A deferred procedure is a deferred argument that can appear in procedure references within a REQUIREMENT construct, TEMPLATE construct, or STP. A deferred procedure's interface shall be established in that construct, possibly in terms of other deferred arguments. A deferred type is a deferred argument that can appear as a , or in a or , within a REQUIREMENT construct, TEMPLATE construct, or STP. Note: A deferred type is not a and cannot not appear in a . Consequently a deferred type may not be used in a . Within a construct with a , an explicit specification of that is either or . A shall have one or more ultimate specifications. The ultimate specifications of a are: - an explicit specification, if present, and - its ultimate specifications as instantiation arguments in REQUIRES statements, if any. The ultimate specifications of an instantiation argument in a REQUIRES statement are the ultimate specifications of the corresponding deferred argument in the referenced requirement construct. Note: The approach here is that a deferred argument is always eventually explicitly declared at some level of nesting of requirements. A deferred argument must have at least one ultimate specification and may have multiple. Note: If a deferred argument has multiple ultimate specifications, they must be consistent. Constraints on consistency are defined in section 3.2. Some examples of declarations of deferred arguments are shown below. INTEGER, CONSTANT :: C(..) ! Sec. 3.1.1 TYPE, DEFERRED :: T ! Sec. 3.1.3 INTERFACE ! Sec. 3.1.2 FUNCTION F(X) TYPE(T), INTENT(IN) :: X TYPE(T) :: F END FUNCTION SUBROUTINE S(Y) TYPE(T), INTENT(INOUT) :: Y END SUBROUTINE END INTERFACE PROCEDURE(F_I) :: G ! Sec. 3.1.2 3.1 Syntax for deferred arguments --------------------------------- A deferred argument declaration statement is used to declare deferred arguments. <> <> <> Constraint: A shall appear in a or as the or of an . Constraint: A shall have at most one explicit specification in a given scoping unit. Constraint: A declaration shall not have an nor shall it appear in an . Note: Deferred arguments are local identifiers and are not externally accessible. <> <> <> <> <> 3.1.1 Syntax for deferred constants <> , :: <> [,]... CONSTANT [,]... <> <> Constraint: An entity declared in shall be INTEGER, LOGICAL, or assumed-length CHARACTER. Note: For now, we explicitly disallow fixed-length character deferred arguments. Partly this is to not prejudice further work on deferred arguments with length type parameters. <> [ ( ) ] Constraint: Each shall appear in of the TEMPLATE, REQUIREMENT or STP in which it appears. Constraint: If appears in , it shall be , , , or . Constraint: If , or appears in , then shall not be specified. Constraint: If appears in , then shall not appear as a lower bound. Note: This prevents non-default lower bounds, and leaves open an avenue for backwards compatible extensions for non-default lower bounds in the future. Note: is part of the TEMPLATE, REQUIREMENT, and STP constructs, and is defined in the other generics syntax papers. <> A is a deferred constant. Some examples of declaring deferred constants are as follows. ! explicit shape integer, constant :: x1 integer, constant :: x2(3) integer, parameter :: v1(2) = [5,15] ! not a deferred constant integer, constant :: x3(v1) ! implied shape integer, constant :: x4(*) integer, constant :: x5(*,*) integer, constant, rank(2) :: x6 ! assumed-or-deferred-rank-spec integer, constant :: x7(..) 3.1.2 Syntax for deferred procedures <> PROCEDURE() [ :: ] Constraint: Each shall appear in of the TEMPLATE, REQUIREMENT or STP in which it appears. <> A is a deferred procedure. A that appears as the or in an is a deferred procedure. 3.1.3 Syntax for deferred types <> TYPE, :: Constraint: Each shall appear in of the TEMPLATE, REQUIREMENT or STP in which it appears. <> DEFERRED <> ABSTRACT <> EXTENSIBLE Constraint: DEFERRED shall appear in each . Constraint: The same shall not appear more than once in a given . <> Constraint: A entity shall not appear as in an EXTENDS attribute. A is a deferred type. A deferred type with the EXTENSIBLE attribute is an extensible derived type.A deferred type with the ABSTRACT attribute is an abstract derived type. A deferred type with the ABSTRACT attribute implicitly has the EXTENSIBLE attribute, which can be confirmed with an explicit inclusion of the EXTENSIBLE keyword in the . Note: The distinction between deferred types that are extensible or not, and deferred types which are abstract or not, helps to ensure a processor can verify a template is internally consistent. For example, a deferred type must not be permitted in a CLASS declaration if it might be instantiated as INTEGER. Additionally, a deferred type must not be permitted in a TYPE declaration if it might be instantiated with an abstract derived type. The following examples illustrate this point: SUBROUTINE S1{T}(X, Y) TYPE, DEFERRED :: T TYPE(T) :: X ! ok CLASS(T) :: Y ! invalid END SUBROUTINE SUBROUTINE S2{T}(X, Y) TYPE, DEFERRED, EXTENSIBLE :: T TYPE(T) :: X ! ok CLASS(T) :: Y ! ok END SUBROUTINE SUBROUTINE S3{T}(X, Y) TYPE, DEFERRED, ABSTRACT :: T TYPE(T) :: X ! invalid CLASS(T) :: Y ! ok END SUBROUTINE TYPE :: EXT_TYPE END TYPE TYPE, ABSTRACT :: ABS_TYPE END ABSTRACT INSTANTIATE S1{INTEGER} ! ok INSTANTIATE S1{EXT_TYPE} ! ok INSTANTIATE S1{ABS_TYPE} ! invalid INSTANTIATE S2{INTEGER} ! invalid INSTANTIATE S2{EXT_TYPE} ! ok INSTANTIATE S2{ABS_TYPE} ! invalid INSTANTIATE S3{INTEGER} ! invalid INSTANTIATE S3{EXT_TYPE} ! ok INSTANTIATE S3{ABS_TYPE} ! ok 3.2 Specification of deferred arguments --------------------------------------- The specification of a deferred argument is explicit if it appears in the outermost scope in which it is a deferred argument. 3.2.1 Specification of deferred constants Constraint: If any ultimate specification of a deferred argument is a deferred constant, then all ultimate specifications of that deferred argument shall be deferred constant. Constraint: All ultimate specifications of a deferred constant shall specify the same type and kind-type parameters. Constraint: If any ultimate specification of a deferred constant is of a non-deferred rank R, then an explicit specification of that deferred constant shall have rank R, and all other ultimate specifications of that deferred constant shall either have deferred rank or have rank R. Constraint: If any ultimate specification of a deferred constant has explicit shape S, then an explicit specification of that deferred constant shall have shape S, and all other ultimate specifications of that deferred constant shall have deferred rank, implied shape, or shape S. If any ultimate specification of a deferred constant has an explicit shape S, then that deferred constant has shape S. Otherwise, if any ultimate specification of that deferred constant has implied shape, then it has implied shape with the same rank. Otherwise it has deferred rank. 3.2.2 Specification of deferred procedures Constraint: If any ultimate specification of a deferred argument is a deferred procedure, then all ultimate specifications of that deferred argument shall be deferred procedure. Constraint: A deferred procedure shall not be referenced with keyword arguments unless it has an explicit specification. Note: Although dummy arguments always have names, they are processor- dependent for deferred procedures without an explicit specification. The constraint above ensures such names cannot be used. Constraint: Except for PURE, SIMPLE, and ELEMENTAL attributes, the characteristics of all ultimate specifications of a deferred procedure shall be consistent. Note: The characteristics of a procedure do not include the names of the dummy arguments, so they need not be the same. Constraint: If any ultimate specification of a deferred procedure is SIMPLE, then an explicit specification of that deferred procedure shall be SIMPLE. Constraint: If any ultimate specification of a deferred procedure is PURE, then an explicit specification of that deferred procedure shall be PURE or SIMPLE. Constraint: If any ultimate specification of a deferred procedure is ELEMENTAL, then an explicit specification of that deferred procedure shall be ELEMENTAL. If any ultimate specification of a deferred procedure is SIMPLE then that deferred procedure is SIMPLE. Otherwise, if any ultimate specification of that deferred procedure is PURE, then it is PURE. If any ultimate specification of a deferred procedure is ELEMENTAL then that deferred procedure is ELEMENTAL. Only an explicit specification of a defines the names of its dummy arguments. 3.2.3 Specification of deferred types Constraint: If any ultimate specification of a deferred argument is a deferred type, then all ultimate specifications of that deferred argument shall be deferred type. If any ultimate specification of a deferred type has the EXTENSIBLE attribute, then the deferred type has the EXTENSIBLE attribute. If all ultimate specifications of a deferred type have the ABSTRACT attribute, or if the deferred type has an explicit specification with the ABSTRACT attribute, then the deferred type has the ABSTRACT attribute. Otherwise the deferred type does not have the ABSTRACT attribute. NOTE: A deferred type with the ABSTRACT attribute is considered an abstract derived type, it can only be an instantiation argument when the corresponding deferred argument has the ABSTRACT attribute. Therefore, if a deferred type has an explicit specification with the ABSTRACT attribute, all of its ultimate specifications must have the ABSTRACT attribute. REQUIREMENT R1{U} TYPE, DEFERRED :: U END REQUIREMENT REQUIREMENT R2{U} TYPE, DEFERRED, EXTENSIBLE :: U END REQUIREMENT REQUIREMENT R3{U} TYPE, DEFERRED, ABSTRACT :: U END REQUIREMENT TEMPLATE T1{T} REQUIRES R1{T} ! valid, non-extensible END TEMPLATE TEMPLATE T2{T} REQUIRES R2{T} ! valid, extensible END TEMPLATE TEMPLATE T3{T} REQUIRES R3{T} ! valid, abstract END TEMPLATE TEMPLATE T4{T} TYPE, DEFERRED :: T REQUIRES R1{T} ! valid, non-extensible END TEMPLATE TEMPLATE T5{T} TYPE, DEFERRED :: T REQUIRES R2{T} ! invalid, explicit decl is not extensible END TEMPLATE TEMPLATE T6{T} TYPE, DEFERRED :: T REQUIRES R3{T} ! invalid, explicit decl is not extensible END TEMPLATE TEMPLATE T7{T} TYPE, DEFERRED, EXTENSIBLE :: T REQUIRES R1{T} ! valid, T is not abstract END TEMPLATE TEMPLATE T8{T} TYPE, DEFERRED, EXTENSIBLE :: T REQUIRES R2{T} ! valid, decls match END TEMPLATE TEMPLATE T9{T} TYPE, DEFERRED, EXTENSIBLE :: T REQUIRES R3{T} ! valid, T is just extensible END TEMPLATE TEMPLATE T10{T} TYPE, DEFERRED, ABSTRACT :: T REQUIRES R1{T} ! invalid, T is abstract END TEMPLATE TEMPLATE T11{T} TYPE, DEFERRED, ABSTRACT :: T REQUIRES R2{T} ! invalid, T is abstract END TEMPLATE TEMPLATE T12{T} TYPE, DEFERRED, ABSTRACT :: T REQUIRES R3{T} ! valid, decls match END TEMPLATE TEMPLATE T13{T} REQUIRES R1{T} REQUIRES R2{T} ! valid, T is extensible END TEMPLATE TEMPLATE T14{T} REQUIRES R1{T} REQUIRES R3{T} ! valid, T is just extensible END TEMPLATE TEMPLATE T15{T} REQUIRES R2{T} REQUIRES R3{T} ! valid, T is just extensible END TEMPLATE 3.3 Deferred argument association --------------------------------- This will be discussed in a subsequent paper. ===END===