To: J3 J3/23-213 From: Brad Richardson Subject: The Use of Deferred Constants to Define Kind and Rank Date: 2023-September-26 Reference: 23-155r2 1. Introduction =============== A design goal of the template feature is that the majority of interface and type checking be done at the time a template is processed, without regards to any actual instantiations of that template. This poses a difficulty in the case that deferred constants are used to specify the kind or rank of a variable. This paper describes the difficulty posed and the possible ways to address the problem, and the rationale for the solution chosen by the generics subgroup. 2. The Problem ============== While deferred constants are constants and one would expect to be able to use them in constant expressions, including specification expressions, their values are not known at the time the template is processed. If a deferred constant is used in an expression to define the kind or rank of an argument of a deferred procedure, it then becomes an NP hard problem (in the general case) to determine if the rank or kind of the dummy and actual argument are the same in a reference to that procedure. Consider the following example. TEMPLATE TMPL(T, R, S) TYPE, DEFERRED :: T INTEGER, CONSTANT :: R INTERFACE SUBROUTINE S(A, B) TYPE(T), INTENT(IN), RANK(R) :: A TYPE(T), INTENT(OUT), RANK(1+R) :: B END SUBROUTINE END INTERFACE CONTAINS SUBROUTINE FOO(C, D, ...) TYPE(T), INTENT(IN), RANK(R) :: C TYPE(T), INTENT(OUT), RANK(R+1) :: D ... CALL S(C, D) END SUBROUTINE END SUBROUTINE Note that in this case it seems clear that D and B will always have the same rank and that the call to S should be valid, but that in the general case of expressions involving deferred constants it may not be easy for the compiler to make that determination. 3. Possible Solutions ===================== 3.1 Deferred Constants Cannot Be Used to Specify Rank or Kind ------------------------------------------------------------- This solution eliminates entire classes of use cases. Subgroup thus quickly rejected this as a possible solution. 3.2 Deferred Kinds or Ranks Are Not Checked When Processing Template -------------------------------------------------------------------- This solution pokes a giant hole in the idea of "strong concepts" and so it was dismissed as well. 3.3 Deferred Expressions as a New Kind of Expression ---------------------------------------------------- This idea involves creating a new kind of expression with constraints in between the constraints of constant and specification expressions. I.e. constant expressions would be allowed in deferred expressions, and deferred expressions would be allowed in specification expressions. Kind type parameters would be required to be deferred expressions, as would the specification of rank. One nuance to this idea is that intrinsic inquiry functions would be deferred expressions if any of their arguments have characteristics that are deferred expressions. With this idea there came multiple possibilities for how interface checking would be done in templates. 3.3.1 Evaluate Whether Deferred Expressions Are the Same -------------------------------------------------------- In the general case this is an NP hard problem. Subgroup quickly abandoned this as a requirement on compilers. 3.3.2 Simple Substitution Allowed When Comparing Expressions ------------------------------------------------------------ This idea would require that compilers be able to do simple substitution of inquiry functions to simplify expressions before comparing them for equality. I.e. in the following declarations, Y and Z would be considered to have the same rank. INTEGER, RANK(N) :: X INTEGER, RANK(N+1) :: Y INTEGER, RANK(RANK(X) + 1) :: Z 3.3.3 Only Syntactically Equivalent Expressions Are the Same ------------------------------------------------------------ This solution requires only direct comparison of symbols in a syntax tree to determine if deferred expressions are the same. For example: INTEGER, RANK(N+M) :: X INTEGER, RANK(N + M) :: Y ! has same rank as X INTEGER, RANK(M + N) :: Z ! does not have same rank as X 4. Chose Solution and Consequences ================================== Subgroup has decided to move forward with the solution describe in Section 3.3.3. This enables the following example to be checked at the time of processing the template. TEMPLATE TMPL(T, R, S) TYPE, DEFERRED :: T INTEGER, CONSTANT :: R INTERFACE SUBROUTINE S(A, B) TYPE(T), INTENT(IN), RANK(R) :: A TYPE(T), INTENT(OUT), RANK(R+1) :: B END SUBROUTINE END INTERFACE CONTAINS SUBROUTINE FOO(C, D, E, ...) TYPE(T), INTENT(IN), RANK(R) :: C TYPE(T), INTENT(OUT), RANK(R+1) :: D TYPE(T), INTENT(INOUT), RANK(R) :: E ... CALL S(C, D) ! Valid CALL S(C, E) ! Invalid END SUBROUTINE END SUBROUTINE This does have a somewhat strange consequence that given the following declarations, X and Y are not considered to have the same rank. INTEGER, CONSTANT :: N INTEGER, RANK(N) :: X INTEGER, RANK(RANK(X)) :: Y Subgroup considered this to be an acceptable compromise between placing burden on the compiler writers, and still providing safety and usability to template authors.