next up previous [pdf]

Next: Current compiler limitations Up: Hybrid-norm and Fortran 2003: Previous: Supporting the hybrid norm

Implementation in Fortran 2003

The Fortran 2003 standard makes Fortran a nearly complete object-oriented language. Fortunately (because it improves the compilers ability to optimize) and unfortunately, the object-oriented language components are not described in a very compact manner. The basic object-oriented construct ia a type. In Fortran 90, types could not contain function pointers and there was no inheritance concept. In Fortran 2003, a type can contain a reference to a function pointer. A type now is broken into two parts separated by contains statement. Above the contains statement variables are defined, below procedure pointers. For example, we can create a type vec which contains a function that can add one vector to another. The type is declared by:
type vec
  real, allocatable :: vals(:)
  contains
   procedure, pass :: add=>add_me
 end type
The => keyword indicates that to access the function we should use the name on the left but the name of the procedure is found on the right. The pass keyword will be described later. Within the module that contains the vec definition, we need to define the add_me function:
 subroutine add_me(vec1,vec2)
   class(vec) :: vec1
   type(vec)  :: vec2
   vec2%vals=vec2%vals+vec1%vals
 end subroutine
Note that vec1 is declared using the class keyword rather than the type keyword. The class keyword indicates that anything of type vec or anything that inherits from vec can call this function. We can access the add function through the standard Fortran call keyword:
 type(vec) :: vec1,vec2
 call vec1%add(vec2)
 
Note how the function definition has two arguments while the call description has a single argument. The pass keyword is the reason for the discrepancy. The pass keyword indicates that the type itself should be passed as the first argument.

An abstract type can also be constructed. An abstract type contains one or more function pointers that haven't been assigned. The abstract type can never be declared. Only types that inherit from it can be declared in a functional unit and only if all function pointers have been assigned. An abstract type is declared with the abstract keyword. The keyword deferred is used for all functions that will be assigned by inherited objects. In addition, you can define the interface of each function using the abstract interface construct. Below is an example of using these features:

type,abstract :: vector
  contains
  procedure(add_dec), pass, deferred :: add
end type 

abstract interface
subroutine add_dec(v1,v2)
  class(vector) :: v1,v2
end subroutine
end abstract interface
We can declare a type that inherits from this vector class using the extends construct:
type, extends(vector) :: vec_real
 real :: vals(:)
 contains
 procedure, pass :: add=>add_real
end type
The function vec_real must have the same interface as the type it extends from with the exception of the first argument which now must be of type vec_real. Note how the abstract interface for the add function defines v2 as a class object. To add two vectors we need them to be the same type. We can check the type of a class object using the select type construct:

subroutine add_real(v1,v2) 
 class(vector) :: v2
 class(vector_real) ::v1
 select type(v2)
   type is(vector_real)
      v1%vals=v1%vals+v2%vals
   end select
end subroutine
Within the type is code block, v2 is assumed to be of type vector_real and all components of vector_real can be accessed.

Fortran 2003 also provides a cleanup feature. The finalize keyword is called when an object is no longer needed (for example, when leaving a subroutine where it has been declared). In the example below, the deleteit function is used remove any memory associated with an object.

type, extends(vector) :: vec_real
 real :: vals(:)
 contains
 procedure, pass :: add=>add_real
 final ::  deleteit
end type
Finally, we need the ability to clone an abstract type. The allocate function now takes a keyword argument source. For example, we can create an object v2 of the same type as v1 even though v1 is of an abstract rather than concrete type.
subroutine cloneit(v1,v2)
  class(vector),pointer :: v1,v2
  allocate (v2,source=v1)
end subroutine
With these extensions to the Fortran language, it is possible to completely separate operator writing from solver writing.



Subsections
next up previous [pdf]

Next: Current compiler limitations Up: Hybrid-norm and Fortran 2003: Previous: Supporting the hybrid norm

2010-11-26