# compile-time Fortran polymorphism with CMake

Fortran polymorphism and generic programming (sets, lists, generators) are consistently the highest ranked survey feature requests for Fortran 202X. Fortran programmers introduce polymorphic procedures and variables into Fortran ≤ 2018 by:

- C++ preprocessor overloading
`#ifdef`

etc. - using Fortran user-defined types, with duplicated procedures for each and every desired type/kind.
- using
`include`

statements with generators

I primarily use the `include`

method, as it is Fortran standard (since Fortran 90) and easy to accomplish from the command line.
That is, it’s compile-time polymorphism.
It’s not a perfect solution, and not true polymorphism since each procedure still requires exactly one type/kind per argument.
However, virtually all of my programs use the same kind (number of bits) for each type of variable (real vs. integer).
That is, either I’m using all `real64`

or `real32`

throughout.
Rarely do I mix real kinds for procedure arguments.
On the other hand, there are those with perfectly valid reasons to mix kinds in a program in certain cases, so this method wouldn’t help them.
However, I think for a majority of Fortran programs, compile-time Fortran polymorphism is so easy to do, it’s worthwhile.

Compile-time Fortran polymorphism enables compiling different source files, which is often necessary where a procedure might accept real or complex inputs.

## Compile-time Fortran polymorphic `REAL`

- in all your Fortran code, for each
`REAL`

variable and function, make`kind=wp`

. For example`polyreal.f90`

:`program polyreal use, intrinsic:: iso_fortran_env implicit none include 'kind.txt' real(wp) :: pi,b integer :: i pi = 4._wp * atan(1._wp) b = timestwo(pi) print *,'pi',pi,'2pi',b contains elemental real(wp) function timestwo(a) result(b) real(wp), intent(in) :: a b = 2*a end function timestwo end program`

- make a command-line options
`-Drealkind=real64`

or`-Drealkind=real32`

etc. by creating`CMakeLists.txt`

:`cmake_minimum_required (VERSION 2.8.12) project(realpoly Fortran) # Polymorphic-like real kind program-wide if(realkind) string(TOLOWER ${realkind} realkind) endif() if(realkind STREQUAL real32) # -Drealkind=real32 file(WRITE kind.txt "integer,parameter :: wp=real32") message(STATUS "real kind: real32") elseif(realkind STREQUAL real64) file(WRITE kind.txt "integer,parameter :: wp=real64") message(STATUS "real kind: real64") elseif(realkind STREQUAL real128) file(WRITE kind.txt "integer,parameter :: wp=real128") message(STATUS "real kind: real128") else() # default to real64 file(WRITE kind.txt "integer,parameter :: wp=real64") message(STATUS "real kind: real64") endif() # your modules and programs add_executable(polyrealdemo polyreal.f90)`

This creates file

`kind.txt`

which is included in a module common to all other modules and your program. In my programs, I typically have a`comm.f90`

that contains various constants including`wp`

. - Generate then build as usual:
`cmake -Drealkind=real64 .. make ./polyrealdemo`

pi 3.1415926535897931 2pi 6.2831853071795862

That uses double-precision real64 variables and functions. The concept is trivially extensible to large programs consisting of many files and modules.

- To then select a different kind and rerun, perhaps to evaluate accuracy vs. runtime tradeoffs (real32 is generally faster than real64, but less accurate):
`cmake -Drealkind=real32 .. make ./polyrealdemo`

pi 3.14159274 2pi 6.28318548

or for quad-precision Fortran real128:

`cmake -Drealkind=real128 .. make ./polyrealdemo`

pi 3.14159265358979323846264338327950280 2pi 6.28318530717958647692528676655900559

The contents of `kind.txt`

are simply like:

```
integer,parameter :: wp=real64
```

## Real and Complex compile-time polymorphism

This is shown by example in signal_subspace. Let me know if you’d like more detailed explanation. It includes different source files for real vs. complex, since the procedure calls (particularly to LAPACK/BLAS) are different for real vs. complex.

## Notes

- Fortran 2018 examples

## Leave a Comment