chw21
chw21

Reputation: 8140

Fortran Function with return type depending on parameters

If you look at the definition of the intrinsic function CEILING it has an optional parameter KIND which can be used to force the return value's integer kind.

Would there be any way to implement my own function in Fortran in such a way as to have the kind, or even better the type of the returned value of a function depend on a parameter? I've tried something like this:

program test_kind
    use iso_fortran_env
    implicit none
    integer(kind=int32) :: a
    print*, kind(a)
    print*, kind(kt(int16))
    print*, kind(kt(int32))
contains
    function kt(kind)
        implicit none
        integer, intent(in) :: kind
        integer(kind=kind) :: kt
        kt = 100
    end function kt
end program test_kind

But it fails with the error:

test_kind.f90:12:21:

         integer(kind=kind) :: kt
                     1
Error: Parameter ‘kind’ at (1) has not been declared or is a variable, 
which does not reduce to a constant expression

Now I know I can use procedure overloading to have the same name associated with different procedures depending on the types of arguments. But I'm asking whether the type of the return value can depend on the value of an argument.

Upvotes: 3

Views: 1691

Answers (2)

Holmz
Holmz

Reputation: 724

Or... Pack your functions into a module and have all the flavours of KT.

MODULE KTM
use iso_fortran_env
implicit none
PRIVATE
INTERFACE Kinder
  MODULE PROCEDURE kt_byte, kt_int !kt_long, kt_long_long
END INTERFACE Kinder
PUBLIC Kinder
contains
  function kt_byte(kind_In)
      implicit none
      integer(KIND=int8_t), intent(in) :: kind_In
      integer(kind=int8_t)             :: kt_byte
      kt_byte = 100
  end function kt_byte

  function kt_Int(kind_In)
      implicit none
      integer(KIND=int16_t), intent(in) :: kind_In
      integer(kind=int16_t)             :: kt_Int
      kt_Int = 200
  end function kt_Int

  function kt_long(kind_In)
      implicit none
      integer(KIND=int32_t), intent(in) :: kind_In
      integer(kind=int32_t)             :: kt_long
      kt_long = 400
  end function kt_long

  function kt_8B(kind_In)
      implicit none
      integer(KIND=c_long), intent(in) :: kind_In
      integer(kind=c_long)             :: kt_8B
      kt_8B = 800
  end function kt_8B
end MODULE KTM

Then use the module where you need the various flavours of the KT function...

program test_kind
use iso_fortran_env
USE KTM  !make sure it is in the -I<path> and/or some -L<path> -l<lib>
implicit none
integer(kind=int32)   :: a
integer(kind=int16_t) :: b
integer(kind=int8_t)  :: c
integer(kind=int64)   :: d
integer(kind=c_long)  :: e
REAL :: f
print*, kinder(a)
print*, kinder(b)
print*, kinder(c)
print*, kinder(d)
print*, kinder(e)
!The following line will give a compile error
!print*, Kinder(f)
end program test_kind

Or if it is not used in a commonly used library, then put the module ahead of the program and follow it with the program... In a single file.

Upvotes: 1

IanH
IanH

Reputation: 21451

No. It is not possible in the standard language, as of F2015 draft. The intrinsic procedures are special in this regard.

Dummy arguments that are data objects are always variables in non-intrinsic procedures.

Kind parameters must be given by constant expressions, and variables are not constants. The rules for nominating the type of an object in a scope are practically more restrictive.

Upvotes: 3

Related Questions