Sage-Code Laboratory
index<--

Code Structure

Fortran has higher level concepts to organize a large program into smaller parts named subprograms. The main program will orghestrate a main logical thread that has branches, loops and jumps. This is called structured programming.

Elements defined:



Note: Structured programming was invented to eliminate the spagetty code syndrom that can be encontered in linear programming. Fortran use to have GO TO statement to jump back and forward in the program using numeric labels. In modern Fortran we no longer use goto statement.

Program

Fotran has a special keyword to define the main program. This is translated to function main() in C, and is the entry point of any fortran application. The main program has a name and two regions: executable region and content region.

First region after program name is the the executable region. You can use this to declare arguments, parameters and local variables but also the main thread of the application. Second is the content region for local functions and subroutines.

syntax pattern
!this is fortran 
program main
   ! declare arguments
   ! declare parameters
   ! declare variables
   ...
   ! program statements
   ...
contains
   ! declare subprograms
   ...
end program

program parameters

Program parameters are declared using statements. The input parameters must be parsed. There are specific variable names and functions available to capture the program parameters.

program exit status

The program terminates when there is an error. If the program do not have errors, the exit status is 0, and can be verified by an external script or in the command line by using command: echo $?. Exit status can be set using 2 methods:

  1. using exit: The main program can have exit status. If the exit status is 0 the program is succesful. If the exit status is not zero but a positive number, that is the error code.
  2. using stop: Main program can be intrerupted using "stop" statement. GNU compiler has exit extension but is not part of the standard. I will try to find out more about "stop" statement.

Subroutine

A subroutine is a subprogram that have a name, input/oturput parameters and side-effects. Subroutine has it's own local scope where you can declare variables. The subroutine can be created in "contains" region of program.

subroutine arguments

The arguments are declared without type in the subroutine signature. These are called formal dummy arguments. At the beginning of the soubroutine, after signature, you can declare every argument intention and set arguments optional by using declarative statements similar to local variables.

return statement

A subroutine can have only one end but many exit points. A subprogram can use return statement many times to create early exit points. Usually return is used for preconditions and is very convenient to intrerupt the subprogram when the job is done.

subroutine results

A subroutine can have one or more results. The results are usually declared similar to arguments, except these are output arguments. You can set the result value as any other variable during subroutine execution. You must prepare the result before return.

calling a subroutine

A subroutine is not executed when is declared but later. It can be called once or many times from main thread or from another subroutine. You can use special statement call to execute a subroutine.

syntax pattern
!declare subroutine
program main
   ! call subroutine
   call test(<arguments>)
contains
   ! test is the subroutine name
   subroutine test(<dumy_arguments>)
      ! declarations statements
      ...
      ! computation statements
      return
   end subroutine
end program

Function

Fortran has enhanced support for functions. A function can return a single result. You can define the dummy result name in the function signature using keyword result. You need to define the result type using declarative statement in the function body like any other variable.

function components

Function Components

function arguments

The arguments are declared without type in the function signature. These are called dummy arguments. At the beginning of the function, after the signature, you can declare every argument type using declarative statements similar to local variables.

calling a function

Functions can be called in main program or subroutines using function name follow by round brackets () that contain list of actual arguments. Functions can be used in expressions.

syntax pattern
!declare functions 
program main
   ! main thread
   type_name:: x, y
   y=fn(x) ! call function
contains
   ! fn is the function name
   function fn(p) result(r)
      ! declaration
      type_name:: p
      type_name:: r
      ...
      ! prepare result
      r = <expression>
   end function
end program

Module

Fortran is a modular language. Modules, are usually stored in external files but can be created in the same file as the main program. You must import a module before you can use it's members. You can import a module using the keyword: "use".

syntax pattern
!declare module
module test
   ! declare module variables
   ...
contains
   ! fn is the function name
   function fn() result(r)
      ! prepare result
      r = <expression>
   end function
end module

!using module
program main
   use test
   y=fn() ! call function
end program

Notes: Modules can be contained in the same file as the main program but also can be in separate files. When using separate files, the compiler can compile multiple modules. You can pass module names as a list of names to the compiler.

Arguments

In Fortran we define dummy arguments and actual arguments. They are not one and the same. Dummy arguments must be defined inside subprograms while actual arguments are values that are transfered to the dumy arguments as copy or references.

problem

Currently, Fortran doesn't allow setting a default value for optional dummy arguments. If declaring a dummy argument as optional, the user must implement special code:

  1. Manually make appropriate checks about whether the actual argument is provided by the caller;
  2. Use a separate variable inside the procedure because the code must not refer the optional dummy arguments if not present.
example
! arguments by name
program main
  integer:: r1,r2,r3
  r1 = suma(2)
  r2 = suma(2,4)
  r3 = suma(2,4,6)
  print *, "r1 = ", r1
  print *, "r2 = ", r2
  print *, "r3 = ", r3
contains
  function suma(a,b,c) result(re)
    integer:: a, b, c, re 
    optional:: b, c
    ! default values 
    integer:: b1, c1
    if (present(b)) b1=b
    if (present(c)) c1=c
    ! prepare result
    re = a + b1 + c1
  end function 
end program
console

>./argname
 r1 =            2
 r2 =            6
 r3 =           12

Note: A call must transfer arguments to a subprogram using one of two association techniques: by position or by name. You can specify the name of the arguments in the call. This is an important feature, useful especially when the posible arguents are many and some are optional. Built-in and standard Fortran functions and subroutines can have optional arguments that you can pass by name.

Receiver arguments

Function and subroutine can modify values of arguments. The new value can propagate back to the actual argument. The literals and the expression results are allways pass by value. Receiver arguments can be pass by reference.

example: outarg.f95
! argument intent (demo)
program main
  integer:: op = 0
  call test(a=2, b=4, re = op)
  print *, "a + b = ", op
contains
  subroutine test(a,b,re)
    integer, intent(in):: a, b  
    integer, intent(out):: re
    ! prepare result
    re = a + b
  end subroutine 
end program
console

>./out
 a = 2, b = 4
 a + b =            6

parameters

In Fortran parameters are not arguments. Parameters are actually local constants. That may be confusing! Parameters are local variables with initial value, protected against change.

example
! local parameter
program main
  integer:: r1,r2,r3
  r2 = avg(2,4)
  print *, "avg = ", r2
contains
  function avg(a,b) result(re)
    integer:: a, b, re 
    integer, parameter:: c = 2
    re = (a + b) / 2
  end function 
end program
console

>./parameter
 r2 =            3

Recursion

Recursive functions are special functions that can call themselves several times with different arguments. Fortran has suport for unlimited recursion. The only limitation is that you can run out of memory.

Banchmark

The following code is doing a well known test called "ackermann function". To understand this function better you can check this article: Wikipedia: Ackerman Function

example: recursion.f95
! ackermann test
program recursion
   integer :: ack
   real::t1,t2
   call cpu_time(t1)
   write(*,*) ack(3, 12)
   call cpu_time(t2)
   write(*,'("time=",f6.4)') (t2-t1)
 end program

 recursive function ack(m, n) result(a)
   integer, intent(in) :: m,n
   integer :: a
   if (m == 0) then
     a=n+1
   else if (n == 0) then
     a=ack(m-1,1)
   else
     a=ack(m-1, ack(m, n-1))
   end if
 end function
console
./recursion
       32765
time=3.4615    
Notice in this test the function is declared recursive. It is not defined inside the program "contains" region but independent. I guess Fortran enable this feature.


Read next: Control Flow