## Control Structures

This section gives a brief introduction to the constructs of the Fortran programming language:

### if Construct

Fortran features three different types of conditionals: arithmetic if (deprecated), logical if, and block if.

#### Arithmetic if

The first FORTRAN version from 1957 introduced the arithmetic `if` conditional that evaluates a numeric expression and then jumps to one of three labeled statements, depending on whether the expression is either negative, zero, or positive:

``if (x * y) 100, 200, 300``

If negative, the statement does a `goto` to the first label (`100`), if zero to the second (`200`), and if positive to the third (`300`). This is equivalent to:

``````if (e < 0) goto 100
if (e == 0) goto 200
goto 300``````

Arithmetic `if` is obsolescent since Fortran 90, and has been removed from the Fortran 2018 standard. Like the `goto` statement, it should not be used anymore.

#### Logical if

The logical `if` conditional was added to FORTRAN IV and allows the execution of a statement depending on a logical or arithmetic expression, using operators. Only a single statement may be declared:

``if (x * y < 0) y = 1``

A line-break following the expression is legitimate, but must be indicated by an ampersand:

``````if (x * y < 0) &
y = 1``````

#### Block if

The block `if` allows the conditional execution of a group of statements, for example:

``````if (a == 0) then
exit
else if (a < 0) then
sum = 0
else
sum = sum + a
end if``````

The conditional was introduced in FORTRAN 77.

### select Switch

The `select case` switch is an alternative to block `if`:

``````select case (grade)
case ('A')
print *, 'Excellent!'

case ('B')
case ('C') ! Or: case ('B', 'C')
print *, 'Well done'

case ('D')
print *, 'You passed'

case ('F')
print *, 'Better try again'

case default
end select``````

You may want to use ranges inside `select case` with `case (begin:end)`:

``````select case (marks)
case (91:100)
print *, 'Excellent!'

case (81:90)
print *, 'Very good!'

case (71:80)
print *, 'Well done!'

case (61:70)

case (41:60)
print *, 'You passed!'

case (:40)
print *, 'Better try again!'

case default
print *, 'Invalid marks'
end select``````

Only parameters can be evaluated in a `select case` construct.

#### select type

The `select type` construct was introduced in Fortran 2003, and lets us execute blocks depending on a type or class of a variable. The following type guard statements are used to match a selector expression:

`type is`
Matches the selector if the dynamic type and kind type parameter values are the same as those specified by the statement
`class is`
Matches the selector if the dynamic type is an extension of the type specified by the statement, and the kind type parameter values specified by the statement are the same as the corresponding type parameter values of the dynamic type of the selector.
`class default`
Executed if selector is not matched by any other type guard statement.

The name of the identifier that becomes associated with the selector can be choosen freely, but must be unique within the construct.

``````type :: vec_type
real :: x, y
end type vec_type

type, extends(vec_type) :: vec3_type
real :: z
end type vec3_type

type, extends(vec3_type) :: color_type
integer :: color
end type color_type

type(vec_type),   target  :: v
type(vec3_type),  target  :: v3
type(color_type), target  :: c
class(vec_type),  pointer :: ptr

v  = vec_type(1.0, 2.0)
v3 = vec3_type(1.0, 2.0, 3.0)
c  = color_type(0.0, 1.0, 2.0, 9)

! Point to either v, v3, or c:
ptr => c

select type (a => ptr)
class is (vec_type)
print *, a%x, a%y

type is (vec3_type)
print *, a%x, a%y, a%z

type is (color_type)
print *, a%x, a%y, a%z, a%color
end select``````

### do Loop

The `do` construct loops over statements until an `exit` occurs:

``````do
a = a + 1
print *, a
if (a > 10) exit
end do``````

The do loop is further similiar to the for loop in other programming languages. Set begin, end, and step size in the head of the loop:

``````integer :: i

do i = 1, 10, 2
print *, i
end do``````

The loop index variable has to be declared a priori. The step size is optional. Before Fortran 2018, it was further possible to name loops:

``````loop: do
a = a + 1
print *, a
if (a > 10) exit loop
end do loop``````

This language feature has been declared obsolescent in favour of `cycle`. The `cycle` statement skips to the next iteration:

``````integer :: i

do i = 1, 10
if (modulo(i, 2) == 0) cycle
print *, i
end do``````

#### Implied do

Implied `do` loops return a number of items, using the syntax (item1, item2, …, itemn, var = initial, final, step), for example:

``````integer :: i

print *, ('Hi there. ', i = 1, 3)``````

The `print` statement will output the string three times. Arrays are often initialised using an implied do loop:

``````integer, parameter :: N = 10

integer :: i
integer :: values(N) = [ (i * 2, i = 1, N) ]``````

The array `values` is filled with `2`, `4`, …, `20`. An implied do loop may be nested into another implied do loop. Starting with Fortran 2018, we can declare the index variable in the implied loop:

``````integer, parameter :: N = 10

integer :: values(N) = [ (i * 2, integer :: i = 1, N) ]``````

#### do concurrent

The Fortran 2008 standard added the `do concurrent` construct that allows easy loop parallelisation and is equivalent to `forall`:

``````integer :: i
real :: a(100)

do concurrent (i = 1:size(a))
a(i) = sqrt(i**i)
end do``````

Inside a `do concurrent` loop, only calls to `pure` functions are allowed. Multiple indices may be declared at once:

``````integer :: x, y
real :: a(8, 16)

do concurrent (x = 1:size(a, 1), y = 1:size(a, 2))
a(x, y) = real(x)
end do``````

Since Fortran 2018, the loop indices may be declared inside the contruct:

``````real :: a(8, 16)

do concurrent (integer :: x = 1:size(a, 1), y = 1:size(a, 2))
a(x, y) = real(x)
end do``````

#### do while

The `do while` loop cycles through statements as long as a given condition is true:

``````do while (i < 5)
i = i + 1
print *, i
end do``````

### forall Loop

The `forall` loop has been introduced with Fortran 95, and declared obsolescent in Fortran 2018 in favour of `do concurrent`. It selects elements in an array by index or index range, with an optional step size. In the following example, the loop statement changes the values of the first three elements of the array to `0`:

``````integer :: a(5) = [ 1, 2, 3, 4, 5 ]
integer :: i

forall (i = 1:3) a(i) = 0

! with explicit step size of 1:
forall (i = 1:3:1) a(i) = 0``````

Furthermore, a mask can be added to the condition of the statement in order to select only specific value, for instance:

``````forall (i = 1:3, a(i) == 0) &
a(i) = 1``````

The mask can be any `pure` function. To allow more than one statement, use the `forall` block statement:

``````forall (i = 3:5)
a(i) = 1
print *, a(i)
end forall
``````

Inside the loop, you can assign `pure` functions to the elements:

``````forall (i = 1:3) &
a(i) = my_func(a(i))
``````

Since Fortran 2018, the `forall` indices can be declared in the loop contruct:

``````real :: a(8, 16)

forall (integer :: i = 1:3)
a(i) = i
end forall``````

### where Statement

The `where` statement is used for masked array assignments. Elements of an array will be modified directly upon given conditions:

``````integer :: a(5) = [ 1, 2, 3, 4, 5 ]

where (a >= 3) &
a = 0``````

You can add `else where` statements to the block form of `where`:

``````where (a > 0 .and. a < 2)
a = 0
else where (a >= 4)
a = 1
end where``````

### block Construct

The `block` construct is available since Fortran 2008, and defines an executable block that can contain declarations. A block may be exited prematurely with `exit`, allowing a control flow similar to using `goto`:

``````real :: a

a = 1024.0

block1: block
real :: b

if (a < 0) exit block1

b = sqrt(a)
print *, b
end block block1``````

The variable `b` declared inside `block1` is not accessible from outside of the construct. The identifier `block1` is optional.