Reputation: 2981
I would like to write a procedure which takes an optional
argument, which may be of type FooType
or of type BarType
, such that this program is valid:
module m
implicit none
type :: FooType
end type
type :: BarType
end type
end module
program mwe
use m
implicit none
type(FooType), allocatable :: foo(:)
type(BarType), allocatable :: bar(:)
call func()
call func([FooType()])
call func([BarType()])
call func(foo)
call func(bar)
end program
My current attempt is:
module m
implicit none
type :: FooType
end type
type :: BarType
end type
interface func
module procedure func_FooType
module procedure func_BarType
end interface
contains
subroutine func_FooType(input)
type(FooType), intent(in), optional :: input(:)
write(*,*) 'foo'
end subroutine
subroutine func_BarType(input)
type(BarType), intent(in) :: input(:)
write(*,*) 'bar'
end subroutine
end module
But this does not work. Compiling with either gfortran 10.1.0
or ifort 2021.1
gives the output
foo
foo
bar
foo
bar
The problem is the final call, to func(bar)
. bar
is not allocated
, and so if it were passed to an optional
argument it would not be present
. However, the procedure which gets called is func_BarType
, which believes its input
is not optional
, and so has no way of checking if input
is present
. Indeed, if I change the input
to be a scalar not an array, the call to func(bar)
crashes at runtime under gfortran.
Upvotes: 0
Views: 179
Reputation: 2981
I think the only way to do this is with a single function which takes an optional polymorphic argument, so:
subroutine func(input)
class(*), intent(in), optional :: input(:)
if (present(input)) then
select type(input); type is(FooType)
! Code for FooType.
type is(BarType)
! Code for BarType.
class default
! Any other class. Probably throw an error.
end select
else
! Code for input not present.
endif
end subroutine
I'm surprised that there doesn't seem to be a way of doing this without using polymorphic types.
Upvotes: 1