How to declare a variable with unknown type?

Hi everyone,

I have a small question as indicated in the title.

Imagine we have a variable var_a and a subroutine that prints whatever the input variable is. Something like that :

subroutine printEverything(input)
????declaration  of input

print*, input

Above how can we declare the input so that any type of var_a (i.e. character, integer, real…) can be printed?

Thanks a lot

1 Like

You can use an unlimited polymorphic variable. I tweeted about this.

An unlimited polymorphic allocatable variable x

class(*), allocatable :: x

can hold any type of variable or object. It can be passed as a class(*) argument. Otherwise it must be disambiguated with SELECT TYPE before being used.

program unlimited_polymorphic
implicit none
type :: date
   integer :: year, month, day
end type date
class(*), allocatable :: x ! unlimited polymorphic
real :: y
x = date(2022,2,17)
call disp(x)
x = "abc"
call disp(x)
x = 2.0 ! x has been assigned to 3 different types
! two lines below are invalid outside type guard
! y = x
! print*,"x=",x
select type(x)
   type is (real)
      ! two lines below are valid inside type guard
      y = 10*x
      print*,"x =",x
end select
print*,"y =",y
call disp(x) ! x can be used as actual argument
call set_real(x,y)
print*,"y =",y
x = 42
call disp(x)
call set_real(x,y)
contains
!
subroutine disp(x)
class(*), intent(in) :: x
! print*,"x =",x ! invalid for class(*) variable
select type (x)
   type is (date)
      print*,"x =",x," is date"
   type is (character (len=*))
      print*,"x = ",x," is character"
   type is (real)
      print*,"x =",x,"is real"
   type is (integer)
      print*,"x =",x,"is integer"
end select
end subroutine disp
!
subroutine set_real(x,y)
class(*), intent(in)  :: x
real    , intent(out) :: y
select type(x)
   type is (real)
      y = x
   class default
      error stop "need x real in set_real, STOPPING"
end select
end subroutine set_real
!
end program unlimited_polymorphic
! output:
!  x =        2022           2          17  is date
!  x = abc is character
!  x =   2.00000000    
!  y =   20.0000000    
!  x =   2.00000000     is real
!  y =   2.00000000    
!  x =          42 is integer
! ERROR STOP need x real in set_real, STOPPING
6 Likes

You can use class(*) :: arg (unlimited polymorfic object) to take any type as input. To print it or do anything useful with it you need to check for its type using select type though so I don’t think you can make a completely generic print routine like that.

EDIT: Just like @Beliavsky showed you right before I pressed submit :sweat_smile:

3 Likes

Thanks @Beliavsky and @plevold. My problem is solved, the suggested method works perfectly.

For future reference, the M_msg module contains several similar examples, including STR(3f),
which converts a list of up to twenty intrinsic type variables to a string. The WRT(3f) procedure uses that to create a routine that can write to multiple files with a single statement. STR(3f) is
useful not just for converting numbers to strings but for building messages for logging, for example. The interesting twist is that it allows multiple optional values.

2 Likes