Chapter 10. Fortran Language
Prev | Part III. Supported computer languages | Next

## Chapter 10. Fortran Language

The new implemention of the Fortran binding of PLplot takes full advantage of the `ISO_C_BINDING` feature of the Fortran 2003 standard, which is supported by all current compilers. The advantage of this approach is that the entire binding is now written in Fortran, so that there is only one library that calling programs need to link against. Furthermore, the binding defines overloaded routines for the case of either single- or double-precision arguments supplied by the calling programme regardless of the floating-point precision of the underlying C library. That makes this binding much easier to use than our previous implementation of the Fortran binding where calling routines were forced to use the same floating-point precision that was configured for the underlying PLplot C library.

Note: in this chapter “Fortran” stands for “Fortran as defined by the Fortran 2003 standard”. Older versions of PLplot supported FORTRAN 77, but the binding for this 40 years old version has been abandoned for quite a few years now. As we now use features from the Fortran 2003 standard, it is no longer appropriate to refer to the language as Fortran 95.

We illustrate the implementation of our Fortran binding using the ``plstring`` API as an example. The summary of the C API for that routine which best serves our purposes here is

    void plstring( PLINT n, const PLFLT *x, const PLFLT *y, const char *string );

The arguments `n`, `x`, `y`, and `string` represent the number of times the string is plotted, the arrays of length `n` which contain the `x, y` values where that string is plotted, and the NULL-terminated C string that contains the ordinary (not wide) characters in the UTF-8 encoding of a unicode glyph to be plotted. The PLplot `PLINT` type is normally defined as the C fundamental type `int32_t`, and the PLplot `PLFLT` type is defined to be one of the two C fundamental types `float` or `double` depending on how the C PLplot library is configured.

Here is an example of one fairly typical Fortran call of `plstring`.

    program test_plplot
        use plplot
        implicit none
        integer, parameter :: my_real  = kind(1.0)
        real(kind=my_real), dimension(6) :: x, y
        ...
        x = ...
        y = ...
        ...
        call plstring(x,y,"+")
        ...
    end program test_plplot

where for this particular case `x` and `y` are arrays with 6 elements defined and the points are to be plotted using the ascii "+" symbol (although if you are using a unicode-aware PLplot device, then you can try many other unicode possibilities for the symbol such as the U+22C5 DOT OPERATOR, "⋅"). Note that our Fortran binding implementation below allows use of the `kind(1.0d0)` choice of `my_real` precision as well.

The `plstring`-relevant parts of the `plplot` module used above are

    module plplot
        ...
        use plplot_single
        use plplot_double
        ...
    end module plplot

The redacted part of the `plplot` module implements the interfaces to the PLplot C library routines that happen to have no floating-point arguments very similarly to the way that the `plplot_single` and `plplot_double` modules interface the PLplot C routines like `plstring` that do include floating-point arguments. The `plstring`-relevant parts of the `plplot_single` module are

    module plplot_single
        ...
        integer, parameter :: wp = private_single
        ...
        interface plstring
            module procedure plstring_impl
        end interface plstring
        private :: plstring_impl
        ...
    contains
        ...
        subroutine plstring_impl( x, y, string )

           real(kind=wp), dimension (:), intent(in) :: x, y
           character(len=*), intent(in) :: string

           integer(kind=private_plint) :: n_local

           interface
               subroutine interface_plstring( n, x, y, string ) bind(c,name='c_plstring')
                   import :: private_plint, private_plflt
                   implicit none
                   integer(kind=private_plint), value, intent(in) :: n
                   real(kind=private_plflt), dimension(*), intent(in) :: x, y
                   character(len=1), dimension(*), intent(in) :: string
               end subroutine interface_plstring
           end interface

           n_local = size(x, kind=private_plint)
           if(n_local /= size(y, kind=private_plint) ) then
               write(error_unit,"(a)") "Plplot Fortran Warning: plstring: inconsistent sizes for x and y"
           end if

           call interface_plstring( n_local, real(x,kind=private_plflt), real(y,kind=private_plflt), &
               trim(string)//c_null_char )
        end subroutine plstring_impl
        ...
    end module plplot_single

The `plstring`-relevant parts of the `plplot_double` module are defined identically (in fact that identicality is guaranteed by using the same included file to define the identical parts) except for

        integer, parameter :: wp = private_double

Here are some notes on the above implementation of our Fortran binding for `plstring`. The `plplot_single` and `plplot_double` modules implement two versions of the Fortran `plstring` subroutine which are identical except one subroutine has floating-point arguments with a kind value of `wp = private_single = kind(1.0)` and one subroutine has floating-point arguments with kind value of `wp = private_double = kind(1.0d0)`. The result is the Fortran compiler automatically chooses the correct overloaded version of `plstring` that corresponds to the precision of the floating-point arguments used by the program (e.g., like `test_plplot` above) that is being compiled. The intrinsic function `size()` is used to determine the size of arrays and allows checking that their dimensions are consistent with each other when the C implementation uses a common size for the arrays as in the `plstring` case. (See also, `bindings/fortran/README_array_sizes`.) The intrinsic function `real()` is used to convert floating-point data between the type used by the calling routine and the type used by the underlying PLplot C library, and the intrinsic function `int()` (not used in the above example) is used for similarly converting integer data. The intrinsic function `trim()` and the `ISO_C_BINDING` parameter `c_null_char` are used to help convert a Fortran character string into a NULL-terminated C string. Also note the above interface block defining `subroutine interface_plstring` is the Fortran representation of the exact C API of `plstring`.

Here is a table summarizing how C data types correspond to Fortran data types in the arguments of functions defined by our Fortran binding. Consult the Fortran code in `bindings/fortran/*` for further details of how the conversion is done between our private Fortran types that are equivalent to the corresponding C types, and the public Fortran types that are available for Fortran function arguments in our Fortran binding. Note the `my_flt` kind value used in this table is not provided by our Fortran binding. Instead it merely indicates that the calling routine (e.g., the `test_plplot` example routine above) has the choice of either `kind(1.0)` or `kind(1.0d0)` for the kind values of the floating-point arguments of the PLplot functions defined by our Fortran binding.

C type | Private Fortran type | Public Fortran type
--- | --- | ---
`PLFLT` | `real(kind=private_plflt)` | `real(kind=my_flt)`
`PLFLT *` | `real(kind=private_plflt), dimension(*)` | `real(kind=my_flt), dimension(:)`
`PLFLT **` | `type(c_ptr), dimension(*)` | `real(kind=my_flt), dimension(:, :)`
`PLINT` | `integer(kind=private_plint)` | `integer`
`PLINT *` | `integer(kind=private_plint), dimension(*)` | `integer, dimension(:)`
`PLBOOL` | `integer(kind=private_plbool)` | `logical`
`char *` | `character(len=1), dimension(*)` | `character(len=*)`

In C there are two ways to pass a variable --- by value (the default) or by reference (pointer), whereas in Fortran this difference is not visible in the call, only in the interface definition via the `value` attribute. Therefore when you see references in the documentation of our C API to either an ordinary argument or a pointer argument (e.g. `*data`), you simply use an ordinary Fortran variable or array name. The new Fortran binding automatically takes care of any conversion that may be necessary.

In sum, the `plstring` example above illustrates the way our Fortran binding makes the PLplot C API conveniently accessible from Fortran while letting the C binding and overloading features of the Fortran compiler hide the complexities of the name mangling that occurs.

Users should be aware that there are a few cases with our new Fortran binding where we provide double-precision floating-point entities but no equivalent single-precision floating-point alternative.

- The Fortran standard dictates that compilers cannot disambiguate overloaded functions based on the type of their return value. This means that the `plrandd` function cannot be disambiguated because it has no arguments. For this reason we have decided to provide only one version of this function that returns a double-precision random value.

- The Fortran standard dictates that compilers cannot disambiguate overloaded routines based on the types of arguments to callback routines that appear as arguments to those routines. This means that the `plstransform` and `plslabelfunc` routines cannot be disambiguated because they have no direct floating-point arguments. For this reason we have decided that for the case where `plstransform` uses a `transform_coordinate` callback as its first argument, that callback will be allowed to only have double-precision arguments. And similarly for `plslabelfunc` and the `label_func` callback.

- The new Fortran binding defines a derived `PLGraphicsIn` type as follows:

        type :: PLGraphicsIn
           integer                   :: type           ! of event (CURRENTLY UNUSED)
           integer                   :: state          ! key or button mask
           integer                   :: keysym         ! key selected
           integer                   :: button         ! mouse button selected
           integer                   :: subwindow      ! subwindow (alias subpage, alias subplot) number
           character(len=16)         :: string         ! Fortran character string
           integer                   :: pX, pY         ! absolute device coordinates of pointer
           real(kind=private_double) :: dX, dY         ! relative device coordinates of pointer
           real(kind=private_double) :: wX, wY         ! world coordinates of pointer
        end type PLGraphicsIn

  This is the type that should be used for the argument of the Fortran `plGetCursor` routine. We provide no alternative `plGetCursor` routine whose argument is similar to `PLGraphicsIn` but with single-precision `dX`, `dY`, `wX`, and `wY` components.

- The new Fortran binding provides three auxiliary floating-point parameters, `PL_PI`, `PL_TWOPI` and `PL_NOTSET` which are all defined in double precision. If the calling routine requires single precision instead it should define a local parameter as in the following code fragment:

          use plplot
          ...
          integer, parameter :: my_flt = kind(1.0)
          real(kind=my_flt), parameter :: my_NOTSET = PL_NOTSET

Users should be aware that the new Fortran binding for PLplot enforces the following interfacing rules:

- The new Fortran binding interfaces Fortran functions/subroutines with C routines if the C routines provide/do not provide a return value. For example, this rule means that the C `plparseopts` routine that returns an error code must be invoked at the Fortran level similarly to the following:

          integer :: plplarseopts_rc
          ...
          plparseopts_rc = plparseopts(...)

  Of course, this rule means it is possible for Fortran routines invoking functions like plparseopts to respond properly to error conditions returned by the corresponding C routine.

- Only the redacted form of Fortran API (with all redundant dimension arguments removed) is supported.

- If the C API for the function being interfaced includes a size value corresponding to identical sizes of dimension(s) of multiple array arguments. then the sizes of the corresponding dimensions of the Fortran arrays must also be identical. The complete list of these adopted rules for consistently sized array arguments for our Fortran binding are given at `bindings/fortran/README_array_sizes`. These rules are enforced in a user-friendly way by issuing a run-time warning whenever these rules have been violated. For those cases which generate such warnings because the calling routine has specified static or allocatable arrays whose relevant defined areas are smaller than their size, use the normal Fortran rules for array slicing to specify completely defined arrays with consistent sizes that comply with this interfacing rule.

- Fortran logical arguments are used for all cases where the corresponding C argument is `PLBOOL`.

- All floating-point arguments for a given function call must have consistent kind values (either `kind(1.0)` or `kind(1.0.d0)`).

For more information on calling PLplot from Fortran, please consult the example Fortran programs in `examples/fortran` that are distributed with PLplot. For more information on building your own PLplot-related Fortran routines, please consult either the traditional (Makefile + pkg-config) or CMake-based build systems that are created as part of the install step for our Fortran (and other language) examples.

Prev | Up | Next
Status of the C++ Interface | Home | Chapter 11. OCaml Language