Why can't I select type is on intrinsic types?

I am trying to write a type-inferring wrapper for MPI that behaves like Numpy+mpi4py.

I looked at https://www.ibm.com/docs/en/xl-fortran-aix/16.1.0?topic=control-select-type-construct-fortran-2003 but it seems that TYPE IS cannot work with intrinsic types, and that I cannot write a generic wrapper, but rather have to write one for every intrinsic type. While not hard, this is annoying and seems to defeat the purpose of having generic programming features in a language.

How do I write the following, without have to create an interface and then specialize on every intrinsic type?

subroutine gen(buffer)
    use iso_fortran_env
    implicit none
    type(*), dimension(..) :: buffer
    select type(buffer)
        type is (real(kind=REAL64))
            print*,'REAL64'
    end select
end subroutine

Thanks!

Jeff

1 Like

@JeffH, use class(*) instead of type(*) if you are looking for something in the short-term i.e., until 20+ years from now when some improved generics in Fortran may be available in some complers post Fortran-202Y.

Caveat emptor with class(*)though.

1 Like

This is an example program that takes up to twenty intrinsic values and converts them to a CHARACTER variable that uses CLASS(*) that shows an example of what you want, I think.

Summary
module anything
use,intrinsic :: iso_fortran_env, only : int8, int16, int32, int64, real32, real64, real128
implicit none
private
public tostr
contains
function tostr(g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, ga, gb, gc, gd, ge, gf, gg, gh, gi, gj, sep)

!$@(#) M_attr::tostr(3fp): converts a message to a string composed of any standard scalar types

class(*),intent(in),optional  :: g0, g1, g2, g3, g4, g5, g6, g7, g8, g9, ga, gb, gc, gd, ge, gf, gg, gh, gi, gj
character(len=:),allocatable  :: tostr
character(len=4096)           :: line
integer                       :: istart
integer                       :: increment
character(len=*),intent(in),optional :: sep
character(len=:),allocatable  :: sep_local
   if(present(sep))then
      increment=len(sep)+1
      sep_local=sep
   else
      increment=2
      sep_local=' '
   endif

   istart=1
   line=''
   if(present(g0))call print_generic(g0)
   if(present(g1))call print_generic(g1)
   if(present(g2))call print_generic(g2)
   if(present(g3))call print_generic(g3)
   if(present(g4))call print_generic(g4)
   if(present(g5))call print_generic(g5)
   if(present(g6))call print_generic(g6)
   if(present(g7))call print_generic(g7)
   if(present(g8))call print_generic(g8)
   if(present(g9))call print_generic(g9)
   if(present(ga))call print_generic(ga)
   if(present(gb))call print_generic(gb)
   if(present(gc))call print_generic(gc)
   if(present(gd))call print_generic(gd)
   if(present(ge))call print_generic(ge)
   if(present(gf))call print_generic(gf)
   if(present(gg))call print_generic(gg)
   if(present(gh))call print_generic(gh)
   if(present(gi))call print_generic(gi)
   if(present(gj))call print_generic(gj)
   tostr=trim(line)
contains

subroutine print_generic(g)
class(*),intent(in) :: g
   select type(g)
      type is (integer(kind=int8));     write(line(istart:),'(i0)') g
      type is (integer(kind=int16));    write(line(istart:),'(i0)') g
      type is (integer(kind=int32));    write(line(istart:),'(i0)') g
      type is (integer(kind=int64));    write(line(istart:),'(i0)') g
      type is (real(kind=real32));      write(line(istart:),'(1pg0)') g
      type is (real(kind=real64));      write(line(istart:),'(1pg0)') g
      type is (real(kind=real128));     write(line(istart:),'(1pg0)') g
      type is (logical);                write(line(istart:),'(l1)') g
      type is (character(len=*));       write(line(istart:),'(a)') trim(g)
      type is (complex);                write(line(istart:),'("(",1pg0,",",1pg0,")")') g
   end select
   istart=len_trim(line)+increment
   line=trim(line)//sep_local
end subroutine print_generic
end function tostr
end module anything

program testit
use,intrinsic :: iso_fortran_env, only : int8, int16, int32, int64, real32, real64, real128
use anything, only : tostr
character(len=:),allocatable :: line
   line=tostr('reals',10.,20.0,30.0d0,'integers',111,22222222222222222_int64,'logicals',.true.,'complex',(30.0,40.0))
   write(*,'(a)')line
   line=tostr((30.0,40.0)*10)
   write(*,'(a)')line
end program testit
1 Like

Thank you. This was a very helpful suggestion. Now I have what I need to build the real thing.

module ok
    contains
    subroutine gen(buffer)
        use iso_fortran_env
        implicit none
        class(*) :: buffer
        select type(buffer)
            type is (real)
                print*,'REAL'
            type is (double precision)
                print*,'DP'
        end select
    end subroutine
end module

program fortran
    use ok
    implicit none
    double precision dp
    print*,kind(dp)
    call gen(dp)
end program
1 Like