# How to generalize the function/subroutine to any data type?

**URL:** <https://fortran-lang.discourse.group/t/how-to-generalize-the-function-subroutine-to-any-data-type/5529>\
**Category:** Uncategorized\
**Created:** [April 9, 2023, 2:02am UTC](https://fortran-lang.discourse.group/t/how-to-generalize-the-function-subroutine-to-any-data-type/5529 "2023-04-09T02:02:16Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![CRquantum](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/crquantum/32/730_2.png) [@CRquantum](https://fortran-lang.discourse.group/u/CRquantum)\
**Post date:** [April 9, 2023, 2:02am UTC](https://fortran-lang.discourse.group/t/how-to-generalize-the-function-subroutine-to-any-data-type/5529/1 "2023-04-09T02:02:16Z")

</div>

Dear all,

I read the small code by @certik  
The code is simply read in a integer matrix A, and output its diagonal elements in array d.

```auto
    function diag(A) result(d)
    integer, intent(in) :: A(:,:)
    integer :: d(size(A,1))
    integer :: i
    do i = 1, size(A,1)
        d(i) = A(i,i)
    end do
    end function

```

Now, if A is complex number, or real number matrix, do we need to write diag function for each of the different types of A?

I know there is elemental function which can smartly use a scalar function for vector function,  
but here, is there a way that Fortran can just use one diag function, and it can smartly apply this function to any data type of the input matrix A?

Things like below for example

```auto
  function diag(A) result(d)
  **type(any)**, intent(in) :: A(:,:)
  **type(A)** :: d(size(A,1))
  integer :: i
  do i = 1, size(A,1)
      d(i) = A(i,i)
  end do
  end function

```

Thanks much!

PS  
Code is from below link,

> <https://github.com/j3-fortran/fortran_proposals/issues/14>
>
> It would be really nice to have a built in (and so highly optimized) operation, …as it is in Matlab: \`diag(A)\` to get or set the diagonal of a matrix A. Or, more generally, diagonal slices to get \*any\* diagonal (whether main or other) or even group of diagonals. Would be the perfect complement to current square submatrix slices.
> 
> See also the Matlab's \[diag\](https://www.mathworks.com/help/matlab/ref/diag.html) function and Python Numpy's \[diag\](https://docs.scipy.org/doc/numpy/reference/generated/numpy.diag.html) function.
> 
> Use cases:
> 
> 1) Getting the diagonal
> \`\`\`fortran
> real(dp) :: A(n, n)
> print \*, diag(A)
> \`\`\`
> 2) Setting the diagonal
> \`\`\`fortran
> real(dp) :: A(n, n)
> A = 0
> diag(A) = 1
> \`\`\`
> 
> 
> Note: The \`diag(A) = 1\` syntax is new, as we are setting something to a result of a function. The way it should be read is that \`diag(A)\` is not a function but rather an intrinsic operation that gives access to the main diagonal. An alternative notation that could be considered:
> 
> 
> 1) Getting the diagonal
> \`\`\`fortran
> real(dp) :: A(n, n)
> print \*, A(\\)
> \`\`\`
> 2) Setting the diagonal
> \`\`\`fortran
> real(dp) :: A(n, n)
> A = 0
> A(\\) = 1
> \`\`\`
> Or more generally \`A(start\\end\\skip)\` for the main diagonal and \`A(start/end/skip)\` for the anti-diagonal. In such case, an optional parameter could occur to denote which diagonal, as in Matlab, e.g., \`A(2\\4,0)\` gets 2nd thru 4th elements of the main diagonal, \`A(2\\4,1)\` gets 2nd thru 4th elements of diagonal above the main, etc.

---

<div class="post-metadata">

**Author:** ![septc](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/septc/32/77_2.png) [@septc](https://fortran-lang.discourse.group/u/septc)\
**Post date:** [April 9, 2023, 2:54am UTC](https://fortran-lang.discourse.group/t/how-to-generalize-the-function-subroutine-to-any-data-type/5529/2 "2023-04-09T02:54:39Z")

</div>

Apart from generic types, we can make a macro for creating a diagonal-matrix view via pointers (based on the linked codes by 🤠 , just for fun…)

```fortran
#define set_diag_view( arr, diag ) \
diag( 1:size(arr) ) => arr; diag => diag( 1::size(arr,1)+1 )

program main
    implicit none
    integer :: n, i
    integer, allocatable, target :: a(:,:)
    real, allocatable, target :: b(:,:)
    integer, pointer :: da(:)
    real, pointer :: db(:)

    print *, "input n:"
    read *, n

    a = reshape( [(i, i=1,n**2)], [n,n] )
    b = a

    set_diag_view( a, da )
    set_diag_view( b, db )

    da(:) = 100
    db(:) = 200.0

    print *
    print *, "n = ", n
    print *, "a = ", a
    print *, "b = ", b
end

$ gfortran test.F90 && ./a.out
 input n:
2

 n = 2
 a = 100 2 3 100
 b = 200.000000 2.00000000 3.00000000 200.000000    

```

---

<div class="post-metadata">

**Author:** ![Euler-37](https://avatars.discourse-cdn.com/v4/letter/e/b19c9b/32.png) [@Euler-37](https://fortran-lang.discourse.group/u/Euler-37)\
**Post date:** [April 9, 2023, 3:01am UTC](https://fortran-lang.discourse.group/t/how-to-generalize-the-function-subroutine-to-any-data-type/5529/3 "2023-04-09T03:01:10Z")

</div>

```auto
module template_array
    implicit none
    private
    public :: test_template

    requirement operations(t)

        type :: t; end type
    end requirement
!
    template array_tmpl(t)

        requires operations(t)
        private
        public :: diag_t

    contains

        subroutine diag_t(a,b)
            type(t), intent(in) :: a(:,:), b(:)
            integer::i
            do i=1,size(b)
                b(i)=a(i,i)
            end do
        end subroutine

    end template

contains

    subroutine test_template()
        instantiate array_tmpl(integer), only: diag_int => diag_t
        instantiate array_tmpl(real), only: diag_r4 => diag_t

        integer :: ai(2,2),di(2)
        real :: ar(2,2),dr(2)
        ai(1,1) = 1;ai(1,2) = 2
        ai(2,1) = 3;ai(2,2) = 4
        call diag_int(ai,di)
        print *, di
        ar(1,1)=1.;ar(1,2)=2.
        ar(2,1)=3.;ar(2,2)=4.
        call diag_r4(ar,dr)
        print *, dr
    end subroutine

end module

program template_array_03

    use template_array
    implicit none

    call test_template()

end program

```

[lfortran](https://dev.lfortran.org/) template,  
but not now

```auto
syntax error: Token '(' is unexpected here
  --> input:35:36
   |
35 | instantiate array_tmpl(real(8)), only: diag_r8 => diag_t
   | ^ 

```

---

<div class="post-metadata">

**Author:** ![shahmoradi](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/shahmoradi/32/3151_2.png) [@shahmoradi](https://fortran-lang.discourse.group/u/shahmoradi)\
**Post date:** [April 9, 2023, 4:26am UTC](https://fortran-lang.discourse.group/t/how-to-generalize-the-function-subroutine-to-any-data-type/5529/4 "2023-04-09T04:26:36Z")

</div>

I think you desire a syntax similar to what I (and many others) wished for in this [post](https://fortran-lang.discourse.group/t/prototype-implementation-of-fortran-generics-in-lfortran/4664/26). Such syntax is not going to be seen in Fortran ever, or anytime soon, based on the discussions in the above thread.

---

<div class="post-metadata">

**Author:** ![certik](https://yyz2.discourse-cdn.com/free1/user_avatar/fortran-lang.discourse.group/certik/32/4_2.png) [@certik](https://fortran-lang.discourse.group/u/certik)\
**Post date:** [April 9, 2023, 5:39am UTC](https://fortran-lang.discourse.group/t/how-to-generalize-the-function-subroutine-to-any-data-type/5529/5 "2023-04-09T05:39:44Z")

</div>

@CRquantum yes, the new generics, being proposed for F202Y and that have a prototype in LFortran will be able to handle this case, you just declare it as generic, write it once, and it will work for all types.
