To: J3 J3/24-105r1 From: Aury Shafran & Brad Richardson Subject: Requirements and specs for simplified template procedures Date: 2024-February-12 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.) 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.) 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. An example of a simplified template procedure using illustrative syntax: 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 b. An STP can be instantiated in the specification section using an INSTANTIATE statement. For example, 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 A1 Curly braces call do_something(x, clone {real} ) 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:> ) Pros: - no new character needed Cons: - two characters - vaguely looks like old syntax typo A3 Double angle-bracket call do_something(x, clone <> ) 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 Pros: - one character - very unambiguous Cons: - "burns" 1 new character - opening and closing are same - confusing - breaks markdown - looks like m4 preprocessor The following are _not_ recommended by subgroup, but could be made to work: B1 Square bracket call do_something(x, clone [real] ) ! confusing? co-arrays? The following just cannot work: C1 Single angle-bracket (C++ like) call do_something(x, clone) Does not work in complicated cases. E.g., call do_something(x, foo(a)) Is this a function invocation of foo with arg a and type parameters real and integer? Or invocation of do_something with 3 arguments: "x", "foo < real", and "integer > a" C2 Simple parens instantiate clone(integer) integer :: real call do_something(x, clone(real)) ! ambiguous Is last line the function clone() called with an integer argument, or is it instantiating a template clone with type real? Subgroup would prefer 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===