# Fortran/language extensions

Like several other languages, Fortran 90 and newer supports the ability to select the appropriate routine from a list of routines based on the arguments passed. This selection is done at compile time and is thus unencumbered by run-time performance penalties. This feature is accessed by use of modules and the interface block.

In the following example, a module is specified with contains a single logical function which can handle arguments of various types.

module extension_mod
implicit none
private

interface f
module procedure f_i
module procedure f_r
module procedure f_z
end interface

public::f

contains

function f_i(x) result(y)
integer,intent(in)::x
integer::y

y = x**2-1
end function f_i

function f_r(x) result(y)
real,intent(in)::x
real::y

y = x**2-1.0
end function f_r

function f_z(x) result(y)
complex,intent(in)::x
complex::y

y = x**2-1.0
end function f_z

end module extension_mod


A program which uses this module now has access to a single logical function f which accepts arguments which are of the integer, real, or complex data types. The return type of the function is the same as the input type. In this way the routine is much like many of the intrinsic functions defined as part of the Fortran standard. An example program is given below:

program main
use extension_mod
implicit none

integer::xi,yi
real::xr,yr
complex::xz,yz

xi = 2
xr = 2.0
xz = 2.0

yi = f(xi)
yr = f(xr)
yz = f(xz)

end program main


## Intrinsic functions

One can extend intrinsic functions. This is similar to overload operators.

Here we will demonstrate this by extending the sqrt function. The intrinsic function is not implemented for arguments of integer type. This is because there is no clear idea how to define the result of non integer type (e.g. ${\displaystyle {\sqrt {4}}=2}$, but how to define ${\displaystyle {\sqrt {5}}=2.236\ldots }$). We implement a method here where the result is always the nearest integer.

module sqrt_int_module

implicit none
private

! use intrinsic sqrt for data types which are not overloaded
intrinsic :: sqrt

! extend sqrt for integers
public :: sqrt
interface sqrt
procedure sqrt_int
end interface sqrt

contains
pure function sqrt_int( int ) result( res )
integer, intent(in) :: int
integer :: res

res = nint( sqrt( real(int) ) )

end function sqrt_int
end module sqrt_int_module

program main
use sqrt_int_module
implicit none

integer :: i

do i = 1, 7
print *, "i:", i, "sqrt(i):", sqrt(i)
end do

end program main


## Derived Data Types

Fortran 90 and newer supports the creation of new data types which are composites of existing types. In some ways this is similar to an array, but the components need not be all of the same type and they are referenced by name, not index. Such data types must be declared before variables of that type, and the declaration must be in scope to be used. An example of a simple 2d vector type is given below.

type::vec_t
real::x,y
end type


Variables of this type can be declared much like any other variable, including variable characteristics such are pointer or dimension.

type(vec_t)::a,b
type(vec_t),dimension(10)::vecs


Using derived data types, the Fortran language can be extended to represent more diverse types of data than those represented by the primitive types.

Operators can be overloaded so that derived data types support the standard operations, opening the possibility of extending the Fortran language to have new types which behave nearly like the native types.

### Assignment

The assignment operator = can be overloaded. We will demonstrate this by the following example. Here, we define how the assignment of a logical type on the left and an integer on the right should be performed.

module overload_assignment

implicit none
private

public :: assignment(=)
interface assignment(=)
procedure logical_gets_integer
end interface assignment(=)

contains
subroutine logical_gets_integer( log, i )
logical, intent(out) :: log
integer, intent(in) :: i

if ( i==0 ) then
log = .true.
else
log = .false.
end if
end subroutine logical_gets_integer

program main
implicit none

logical :: log

log = 0
print *, "log=0:", log          ! yields: T

log = 1
print *, "log=1:", log          ! yields: F

end program main


### Intrinsic operators

One can overload intrinsic operators, such as +,-,*.

In the following example we will overload the * operator to work as the logical .and..

module overload_operator

implicit none
private

public :: operator(*)
interface operator(*)
procedure logical_and
end interface operator(*)

contains
pure function logical_and( log1, log2 ) result( log_res)
logical, intent(in) :: log1, log2
logical :: log_res

if ( log1 .and. log2 ) then
log_res = .true.
else
log_res = .false.
end if
end function logical_and

program main
implicit none

logical, parameter :: T = .true., F = .false.

print *, "T*T:", T*T                  ! yields: T
print *, "T*F:", T*F                  ! yields: F
print *, "F*T:", F*T                  ! yields: F
print *, "F*F:", F*F                  ! yields: F

end program main


### New operators

One can create newly self-created operators.

We demonstrate this by the following example: We create an operator .even. <int> which outputs a logical if the given integer is even.

module new_operator

implicit none
private

public :: operator(.even.)
interface operator(.even.)
procedure check_even
end interface operator(.even.)

contains
pure function check_even( int ) result( log_res )
integer, intent(in) :: int
logical :: log_res

if ( modulo( int, 2 )==0 ) then
log_res = .true.
else
log_res = .false.
end if
end function check_even
end module new_operator

program main
use new_operator
implicit none

integer :: i

do i = 1, 6
print *, "i:", i, "even?", .even. i
end do

end program main