veryreverie
veryreverie

Reputation: 2981

Overloading functions with optional arguments

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

Answers (1)

veryreverie
veryreverie

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

Related Questions