In object-oriented languages such as C++, one can define classes that contain both data and methods which operate on that data. One can then create separate instances of the class, each with its own data. A method called from an instance of the class will work on the data held by that particular instance.
In Fortran, modules may contain data, but there is no notion of separate instances of a module. In order to obtain class-like behavior, one can combine a module, which contains the methods that operate on the class, with a derived type containing the data. There can be separate “instances” of the type in that we can allocate many variables of that type which can be passed as parameters to the methods contained in the module.
To illustrate these points consider a simple Circle class, based on an example in Akin (2003, p. 34):
module class_Circle
implicit none
private
public :: Circle, circle_area, circle_print
real :: pi = 3.1415926535897931d0 ! Class-wide private constant
type Circle
real :: radius
end type Circle
contains
function circle_area(this) result(area)
type(Circle), intent(in) :: this
real :: area
area = pi * this%radius**2
end function circle_area
subroutine circle_print(this)
type(Circle), intent(in) :: this
real :: area
area = circle_area(this) ! Call the circle_area function
print *, 'Circle: r = ', this%radius, ' area = ', area
end subroutine circle_print
end module class_Circle
program circle_test
use class_Circle
implicit none
type(Circle) :: c ! Declare a variable of type Circle.
c = Circle(1.5) ! Use the implicit constructor, radius = 1.5.
call circle_print(c) ! Call a class subroutine
end program circle_test
NOTE: circle_print
and circle_area
could be made accessible through generic procedure names print
and area
, respectively. That gets closer to a standard OOP language, because print
can be defined for multiple “sub-classed” objects.
New features in Fortran 2003 allow us to improve upon the object-oriented approach above by using type-bound procedures which allow us to write
a = c%area
call c%print
instead of the more verbose
a = circle_area(c)
call circle_print(c)
If the above example is modified to provide print
and area
as generic interfaces, it is more concise, even though it does not follow modern OOP syntax:
a = area(c)
call print(c)
The program above, modified to use type-bound procedures, looks like this
module class_Circle
implicit none
private
real :: pi = 3.1415926535897931d0 ! Class-wide private constant
type, public :: Circle
real :: radius
contains
procedure :: area => circle_area
procedure :: print => circle_print
end type Circle
contains
function circle_area(this) result(area)
class(Circle), intent(in) :: this
real :: area
area = pi * this%radius**2
end function circle_area
subroutine circle_print(this)
class(Circle), intent(in) :: this
real :: area
area = this%area() ! Call the type-bound function
print *, 'Circle: r = ', this%radius, ' area = ', area
end subroutine circle_print
end module class_Circle
program circle_test
use class_Circle
implicit none
type(Circle) :: c ! Declare a variable of type Circle.
c = Circle(1.5) ! Use the implicit constructor, radius = 1.5.
call c%print ! Call the type-bound subroutine
end program circle_test
Note that we have changed the dummy parameters from type(Circle)
to class(Circle)
. We can then call the class functions in an object-oriented fashion as a = c%area
and call c%print
, where the type is passed to the first argument of the functions circle_area
and circle_print
automatically. See Metcalf, Reid, and Cohen (2004, p. 279) for additional information.
Akin, E. (2003). Object-Oriented Programming Via Fortran 90 and 95. Cambridge University Press. (pdf)
Bader, Reinhold (2007). Object-Oriented Features in Fortran 2003. Slides.
Chin, L. S., D. J. Worth and C. Greenough (2006): Thoughts on using the Features of Fortran 95, Software Engineering Group Notes SEG-N-003 (html | pdf )
Clerman, Norman S. and Spector, Walter (2012). Modern Fortran: Style and Usage. Cambridge University Press.
Cohen, M. (1999): Object orientation and Fortran 2002: part II, ACM SIGPLAN Fortran Forum, 18, 14–21.
Decyk, V. K., C. D. Norton, and B. K. Szymanski: Object Oriented Fortran 90 Programming
Decyk, V. K., and H. Gardner, Object-Oriented Design Patterns in Fortran 90/95: mazev1, mazev2 and mazev3, Computer Physics Communications, 178, pp 611-620 (2008).
Gray, M. G. and R. M. Roberts (1997): Object-based programming in Fortran 90 (PDF, 183K). Computers in Physics, 11, 355–361.
Holcomb, K. (2000): Object-oriented programming in Fortran 95 (PDF, 90K).
Lemmon, D. R. and J. L. Schafer. (2005). Developing Statistical Software in Fortran 95. Springer.
Markus, A. (2006): Design patterns and Fortran 90/95, ACM SIGPLAN Fortran Forum, 25, 13–29.
Markus, A. (2012). Modern Fortran in Practice. Cambridge University Press.
Metcalf, M., J. Reid, and M. Cohen (2004). Fortran 95/2003 Explained. Oxford University Press.
Rouson, D., H. Adalsteinsson, and J. Xia (2010). Object-Oriented Design Patterns for Multiphysics Modeling in Fortran 2003 and C++. ACM Transactions on Mathematical Software.
Worth, D. J. (2008). State of the art in object oriented programming with fortran. Technical Report RAL-TR-2008-002.