Skyy2010
Skyy2010

Reputation: 855

fortran call subroutine depending on kind value error

I want to call a subroutine depending on the kind value of the argument. I tried the following, but I get an error.

parameter, integer:: kind=4
integer(kind):: variable

if (kind==8) then
    call routine_kind8(variable)
elseif(kind==4) then
    call routine_kind4(variable)
endif

I get the following error:

call routine_kind8(variable)
                   1
Error: Type mismatch in argument 'variable' at (1); passed INTEGER(4) to INTEGER(8)

How can I prevent this from happening?

The subroutine routine_kind8 could be defined is defined as follows:

subroutine routine_kind8(variable)
implicit none
integer(8), intent(in):: variable

call api_write_data_to_file(variable)

end subroutine routine

where api_write_data_to_file is a function from an api which can accept any kind type. However, I can not dynamically define kind types in the argument list. Therefore it is necessary for me to call different versions of this routine, based on the kind type of the variable. I can or more precisely don't want to call api_write_data_to_file directly. Instead I want to call it inside routine_kind8

Upvotes: 1

Views: 619

Answers (2)

Alexander Vogt
Alexander Vogt

Reputation: 18098

If you are using a fairly recent compiler, you might look into unlimited polymorphism to achieve your goal. Then, you can even pass different types to the same subroutine:

module test_mod
contains
  subroutine print_type( input )
    class(*),intent(in)  :: input

    select type(input)
    type is (integer(kind=4))
      print *, "Got an integer of kind 4"
    type is (integer(kind=8))
      print *, "Got an integer of kind 8"
    type is (real)
      print *, "Got a real number"
    type is (complex)
      print *, "Got a complex number"
    end select
  end subroutine
end module

program test
use test_mod

  call print_type( 1_4 )
  call print_type( 1_8 )
  call print_type( 1. )
  call print_type( (1.,1.) )

end program

You can use the select case statement to further decide how to proceed and which further subroutines to call. Or, skip the select case statement alltogether and pass everything to api_write_data_to_file directly.

Alternatively you could create an interface block for api_write_data_to_file() in the same manner:

  interface api_write_data_to_file
    subroutine api_write_data_to_file(variable)
      class(*),intent(in)  :: variable
    end subroutine
  end interface

Then, you do not need a wrapper to call api_write_data_to_file().

Upvotes: 6

francescalus
francescalus

Reputation: 32366

An if construct with constant expression conditions is not the same thing as conditional compilation. Dead code elimination also doesn't apply to ensure that only one of the blocks is processed.

What that means is that, when you have the declaration integer(kind=4) variable you do still have a line saying

call routine_kind8(variable)

which is expecting an integer(kind=8) argument.

You could use conditional compilation with a pre-processor, for example, but a far better approach could be to use generic resolution:

parameter, integer:: kind=4
integer(kind):: variable

call routine(variable)

where around the creation of routine_kind4 and routine_kind8 there has been something like

interface routine
  procedure routine_kind4    ! Defined at some point
  procedure routine_kind8
end interface

Upvotes: 0

Related Questions