Are your comments aimed at functions/subroutines, derived types, or both?
For derived types you have the parameterized version, which give you the generic kind. I’ve got an example of a PDT for LU factorization of a square matrix available here.
The derived type comes together quite easily:
type :: lu_workspace(wp,n)
integer, kind :: wp
integer, len :: n
real(wp) :: a(n,n)
real(wp) :: b(n)
integer :: ipiv(n)
logical :: factorized = .false.
end type
Problems show up when you start adding procedures. In that case you cannot avoid boilerplate (without resorting to preprocessing):
integer, parameter :: sp = kind(1.0e0)
integer, parameter :: dp = kind(1.0d0)
interface factorize
module procedure factorize_sp
module procedure factorize_dp
end interface
contains
subroutine factorize_sp(this,info)
use lapack, only: lapack_factorize => sgetrf
type(lu_workspace(sp,*)), intent(inout) :: this
integer, intent(out), optional :: info
include "lu_pdt.inc"
end subroutine
subroutine factorize_dp(this,info)
use lapack, only: lapack_factorize => dgetrf
type(lu_workspace(dp,*)), intent(inout) :: this
integer, intent(out), optional :: info
include "lu_pdt.inc"
end subroutine
I will note that in this usage case, the underlying LAPACK is only available in single and double precision, so declaring them up-front makes sense to me (in a perfect world, we’d also have a generic LAPACK).
I can merely suggest you have a look and participate in the j3-fortran/generics repository.