4

How would one go about using ISO Fortran Env's intrinsic to set a function's return KIND value in a manner which is idiomatic to Fortran 2008?

Normally within the main program, I can just use the ISO Fortran intrinsics as follows:

program name here
    use iso_fortran_env
    implicit none
    integer, parameter :: double=REAL64
    real(kind=double) :: some_variable
end program name here

But there doesn't seem to be a convenient way to use these intrinsics for external functions, since REAL64 and double would both be defined only within the main function above. Attempting to define the function's KIND within main as follows:

program name here
    use iso_fortran_env
    implicit none
    integer, parameter :: double=REAL64
    real(kind=double) :: some_function
    ! Do stuff
end program name here
real function some_function()
    ! Do stuff
end some_function

At least on my system, throws a type mismatch error (double gets defined as KIND=8, and a default real gets defined as a KIND=4 on my system). I could always just use real(kind=8) function some_function(), but I'd prefer not to in the interest of portability. Plus, it just feels dirty to use REAL64 from iso_fortran_env in one place, only to turn around and use KIND=8 in another place.

Is there an easy (or at least, readable) way to accomplish that, such as below?

real(kind=REAL64) function some_function()
AmphotericLewisAcid
  • 1,824
  • 9
  • 26

3 Answers3

5

You start your question offers a solution at the and that solutions works well. As IanH points out there is some ambiguity in the standard wording, but I read it as saying it is allowed and compilers do accept this syntax:

fundef.f90:

real(kind=REAL64) function some_function()
  use iso_fortran_env
  some_function = 1._real64
end

compile:

> gfortran -c funkind.f90 
> 

You can use the kind defined in a module used inside the function. Tested also with Intel Fortran and Oracle Studio.

In modern Fortran all functions should be defined in a module anyway, but if you wish to you a kind from a module used only inside the function, the possibility is here.

  • 1
    Interp F90/0145 deals with this. It is unresolved, and has been that way for over two decades. Given that, I think describing this as "completely legal" might be a bit contentious. – IanH May 30 '18 at 10:14
  • I wasn't actually sure about that word and I even thought I left it out, but apparently not. – Vladimir F Героям слава May 30 '18 at 11:11
  • I actively avoid using this approach because of how this "contentiousness" shows up. It just isn't worth working out how a compiler treats this even if it appears to accept the syntax. – francescalus May 30 '18 at 11:55
  • I have opened the interp, but I read it as referring to finer details, mainly non-constant entities and inquiry functions acting on them. Namely this seems to agree with correctness of this `A named constant can appear in a of a function statement if it is accessible within the function by host or use association.` Answer to point a) in F90/0145 in https://j3-fortran.org/doc/year/17/17-006.txt – Vladimir F Героям слава May 30 '18 at 12:04
  • That interp response was rejected, for whatever reason. Further work on the interp might change that answer, or perhaps it could be put forward and passed without change - we just don't know. I can understand why caution is needed with that interp, as the sequencing requirements of the language are complicated enough as it is. I take the same approach as francescalus in the meantime. – IanH May 31 '18 at 02:19
  • This approach seems to work in Gfortran for both Fortran 2008 and Fortran 90. I'm aware that defining functions in modules is the proper way to do things, but this was just a short script for personal use anyway. Thank you! – AmphotericLewisAcid Jun 01 '18 at 22:22
4

Extending @chw21 's answer:

You always have the option to declare the type of a function result in the specification part of the function, and access parameters from modules by host association inside there.

Edit: «As pointed by @Vladimir F, you can also access variables by host association from a module declared inside the function body.»

In fact, this is the only way to apply attributes to the function result, like pointer, allocatable, dimension etc.

Moreover, you can also declare a new name for the function result through the result suffix.

pure function some_other_function_with_a_long_name() result(out)
    use, intrinsic :: iso_fortran_env, only: rk => real64
    implicit none
    real(rk), dimension(5) :: out
    out = 1.0_rk
    ! (...)
end
Rodrigo Rodrigues
  • 7,545
  • 1
  • 24
  • 36
  • I was originally planning to ask about pure functions, but figured I would distill it down to just a simple "dirty" function. I'm really glad to hear this is still possible with pures. – AmphotericLewisAcid Jun 01 '18 at 22:24
2

I usually try it before posting, but I think this should work:

function some_function()
    use iso_fortran_env, only: real64
    implicit none
    real(kind=real64) :: some_function
    some_function = 1.0_real64
end function some_function

Or inside a module

module some_module
    use iso_fortran_env, only: real64
    implicit none
contains
    real(kind=real64) function some_function()
        some_function=1.0_real64
    end function some_function
end module some_module
chw21
  • 7,970
  • 1
  • 16
  • 31