\( \newcommand\D{\mathrm{d}} \newcommand\E{\mathrm{e}} \newcommand\I{\mathrm{i}} \newcommand\bigOh{\mathcal{O}} \newcommand{\cat}[1]{\mathbf{#1}} \newcommand\curl{\vec{\nabla}\times} \newcommand{\CC}{\mathbb{C}} \newcommand{\NN}{\mathbb{N}} \newcommand{\QQ}{\mathbb{Q}} \newcommand{\RR}{\mathbb{R}} \newcommand{\ZZ}{\mathbb{Z}} \)
UP | HOME

OOP - Fortran

Table of Contents

1. Introduction

The basic idea is that "object oriented programming" in Fortran amounts to:

  • Class approximated by "derived types" in Fortran
  • Instance is a concrete object allocated in memory
  • Component or Field is a "slot" in the class
  • Method is a subroutine or function associated with a field

1.1. Example

Here's an example of a class, namely Shape:

type Shape
   integer :: color
   logical :: filled
   integer :: x
   integer :: y
end type Shape

Caution: fields are public by default in Fortran. To make fields private, we could do the following:

type Shape
   integer, private :: color
   logical, protected :: filled
   integer :: x
   integer :: y
end type Shape

1.2. Suggestions

  • If writing a class (like Shape), place the code in a module (like shape_mod) which is inside its own file (named shape_mod.f90)
    • I've come to like writing Shape_class.f90 as the file name, and module Shape_class for the module name (although I'm certain, I will change my mind soon enough)
  • Consider using PascalCase for class names

2. Constructors

There are a few default constructors provided:

Shape(0, .false., 3, 7) ! Initialize with positional arguments
Shape(x = 5, color = 33, y = 1, filled = .false.) ! keyword arguments

2.1. Custom Constructor

We can override the default constructor to have a smart constructor, using Fortran's interfaces.

pure type(Shape) function new_shape(x, y, color) result(res)
  integer, intent(in) :: x, y, color
  res%color = color
  res%filled = .true.
  res%x = x
  res%y = y
end function new_shape

We could even do some validation on the inputs provided. But now comes the fancy part, where we use an interface to bind Shape's constructor to new_shape(x, y, color):

interface Shape
   module procedure :: new_shape
end interface Shape

3. Binding Methods to a Class

We just need to add a contains to our type declaration, and specify we're passing self along as a parameter:

module Shape_class
  implicit none
  type Shape
     integer :: color
     logical :: filled
     integer :: x
     integer :: y
   contains
     procedure, pass(self) :: area
  end type Shape

contains
  pure integer function area(self)
    type(Shape), intent(in) :: self
    area = self%x * self%y
  end function area

end module Shape_class

CAUTION: when doing polymorphism, instead of writing type(Shape), you need to write class(Shape), so that any children of Shape can use area.

4. References

  • Milan Curcic, Modern Fortran, chapter 8.

Last Updated 2022-02-10 Thu 14:29.