To: J3 J3/24-105r2 From: Aury Shafran & Brad Richardson Subject: Requirements and specs for simplified template procedures Date: 2024-February-27 References: 24-107, 22-120r5, 22-151r3, 22-154r5, 23-007r1 1. Introduction =============== There have been comments that the current template syntax is verbose. This paper proposes a simplified method for the common case where a template contains only a single procedure. We will call these "simplified template procedures" (STP). Note: This paper introduces illustrative syntax that uses curly braces rather than parentheses for deferred argument lists and instantiation argument lists. Our motivation is to avoid ambiguity in the syntax where an STP is instantiated and the resulting procedure is referenced in a single statement. (See final example below.) A clarifying example is provided here for the canonical swap template. The existing verbose syntax permits the following implementation: template swap_tmpl(T) type, deferred :: T contains subroutine swap(a, b) type(T), intent(inout) :: a, b type(T) :: tmp tmp = a a = b b = tmp end subroutine swap end template ... instantiate swap_tmpl(my_T) instantiate swap_tmpl(real), only: swap_real => swap instantiate swap_tmpl(integer), only: swap_integer => swap ... call swap(a, b) call swap_real(x,y) call swap_integer(i,j) Illustrative syntax for a simplified version is the following: subroutine swap{T}(a, b) type, deferred :: T type(T), intent(inout) :: a, b type(T) :: tmp tmp = a a = b b = tmp end subroutine swap ... ! Long form instantiation: instantiate swap{my_T} call swap(a,b) ! Inline instantiation call swap{real}(x, y) call swap{integer}(i, j) 2. Requirements =============== Requirements for STPs: a. It should be possible to easily convert an existing, non-templated, procedure to an STP. b. An STP should support deferred arguments, analogous to those of an ordinary template construct. c. It should be possible to reference an instantiation of an STP as a normal procedure. d. It should be possible to instantiate an STP and reference the resulting procedure in a single statement. It should also be possible to separately instantiate an STP to be referenced subsequently. e. An STP should enforce type-safety (aka "strong concepts"). f. Instantiations of an STP with the same instantiation arguments should be the same procedure. (As with normal templates.) g. An STP shall be defined within a program unit. 3. Specifications ================= a. An STP definition is a procedure definition with additional syntax to accommodate a deferred argument list. The specification section of an STP is the union of a template-specification-part and a specification-part. b. An STP can be instantiated in the specification section using an INSTANTIATE statement. For example (see example in introduction): instantiate swap{real} real :: a, b a = 1.0 b = 2.0 call swap(a, b) c. The single statement instantiation-plus-reference of an STP should look like a conventional procedure reference with minimal additional syntax for deferred Example 1: Single statement invocation: real :: a, b a = 1.0 b = 2.0 call swap{real}(a, b) Example 2: Single statement declarations ! instantiate initial target of procedure pointer procedure(), pointer :: my_swap => swap{real} ! provide interface for dummy procedure procedure(swap{real}) :: dummy_proc Example 3: Single statement procedure actual argument call do_something(x, swap{real}) Straw vote: What is the preferred syntax for template arguments in a single invocation statement? type(T) function clone(T)(x) type, deferred :: T type(T) :: x clone = x end function requirement abstract interface logical function I_compare(x,y) type(T) :: x, y end function end interface end function sorted(T, less, greater)(x) type, deferred :: T procedure(I_Compare) :: less, greater type(T), intent(in) :: x(:) type(T), allocatable :: sorted(:) ... end function logical function greater(T, less)(x, y) type, deferred :: T procedure(I_Compare) :: less type(T), intent(in) :: x, y greater = (.not. less(x,y)) .and. less(y,x) end A1 Curly braces call do_something(x, clone{real}) a = sorted{my_T,operator(<),greater{my_T,operator(<)}}(b) Pros: - one character - very unambiguous Cons: - "burns" 2 new characters - confusing to coders from other languages? A2 Angle-bracket-colon call do_something(x, clone <:real:> ) a = sorted<:my_T,operator(<),greater<:my_T,operator(<):>:>(b) Pros: - no new character needed Cons: - two characters - vaguely looks like old syntax typo A3 Double angle-bracket call do_something(x, clone <> ) a = sorted<>>>(b) Pros: - no new character needed - looks a bit like analogous C++ template args Cons: - two characters - vaguely like CUDA triple-brackets <<< ... >>> esp in nested case: t1<>>> A4 Back-tick (grave accent) call do_something(x, clone `real` ) ! new char a = sorted`my_T,operator(<),greater`my_T,operator(<)``(b) Pros: - one character - very unambiguous Cons: - "burns" 1 new character - opening and closing are same - confusing - breaks markdown - looks like m4 preprocessor Other possibilities were considered and rejected by subgroup as unworkable: - square brackets - confusing with coarrays and array constructors - single angle-bracket - confusing with expressions - simple parens - ambiguous with procedure references Note: Subgroup prefers to use the same syntax for all deferred argument lists and instantiation argument lists. The syntax paper will be updated based upon the outcome of this straw vote. ===END===