7.5 Superclass m4 Macros

The ``superclass'' set of m4 macros is used to automatically create a superclass module that will dynamically dispatch superclass calls to the correct subclass routine or function. This achieves run-time polymorphism, which is commonly considered to be too much effort in Fortran 90, in an easily implemented fashion.

To use the ``superclass'' set of m4 macros certain naming and coding conventions must be followed. Assuming that the superclass name is ``Matrix'', that three subclasses exist named ``One'', ``Two'', and ``Three'', and that the routine to be dynamically dispatched is named ``Solve'', the following names must be used:

superclass derived type: Matrix_type
subclass derived types: One_type, Two_type, Three_type
subclass module names: One_Class, Two_Class, Three_Class
superclass module name: Matrix_Class
superclass routine name: Solve_Matrix
superclass interface name: Solve
subclass routine names: Solve_One, Solve_Two, Solve_Three
subclass interface name: Solve

In addition, the superclass derived type must be:

  type Matrix_type
    character (len=80) :: Subclass
    type(One_type) :: One
    type(Two_type) :: Two
    type(Three_type) :: Three
  end type Matrix_type
To use the superclass macros in the CÆSAR Code Package,

Take the following code segment as an example:

define([SUPERCLASS],[Matrix])
define([SUBCLASSES],[One Two Three])

module SUPERCLASS[]_Class

  SUPERCLASS_USE_ASSOCIATIONS
  SUPERCLASS_TYPE

contains

  SUPERCLASS_ROUTINE([Initialize],
                     [type(real)], [a], [The a variable],
                     [type(integer), intent(in)], [b], [The b variable])

  SUPERCLASS_FUNCTION([Verify_State], [type(logical)],
                      [type(real)], [b], [The b variable])

  SUPERCLASS_ROUTINE([Finalize],
                     [type(real)], [c], [The c variable],
                     [type(real)], [d], [The d variable])

end module SUPERCLASS[]_Class

This code is expanded by Gnu m4 into the following valid F90 code:

module Matrix_Class

  use One_Class
  use Two_Class
  use Three_Class

  type Matrix_type
    character (len=80) :: Subclass
    type(One_type) :: One
    type(Two_type) :: Two
    type(Three_type) :: Three
  end type Matrix_type

contains

  subroutine Initialize_Matrix (Matrix, a, b)

    type(Matrix_type) Matrix
    real (kind=KIND(1.0d0)) :: a ! The a variable 
    integer (kind=KIND(1)), intent(in) :: b ! The b variable 

    !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    select case (Matrix%Subclass)
    case ("One")
      call Initialize (Matrix%One, a, b)
    case ("Two")
      call Initialize (Matrix%Two, a, b)
    case ("Three")
      call Initialize (Matrix%Three, a, b)
    case default
      write (6,*) 'Error: no ', Matrix%Subclass, ' in Matrix_Class.'
    end select

  end subroutine Initialize_Matrix

  function Verify_State_Matrix (Matrix, b)

    type(Matrix_type) Matrix
    logical (kind=KIND(.true.)) :: Verify_State, Verify_State_Matrix
    real (kind=KIND(1.0d0)) :: b ! The b variable

    !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    select case (Matrix%Subclass)
    case ("One")
      Verify_State_Matrix = Verify_State (Matrix%One, b)
    case ("Two")
      Verify_State_Matrix = Verify_State (Matrix%Two, b)
    case ("Three")
      Verify_State_Matrix = Verify_State (Matrix%Three, b)
    case default
      write (6,*) 'Error: no ', Matrix%Subclass, ' in Matrix_Class.'
    end select

  end function Verify_State_Matrix

  subroutine Finalize_Matrix (Matrix, c, d)

    type(Matrix_type) Matrix
    real (kind=KIND(1.0d0)) :: c ! The c variable 
    real (kind=KIND(1.0d0)) :: d ! The d variable 

    !~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

    select case (Matrix%Subclass)
    case ("One")
      call Finalize (Matrix%One, c, d)
    case ("Two")
      call Finalize (Matrix%Two, c, d)
    case ("Three")
      call Finalize (Matrix%Three, c, d)
    case default
      write (6,*) 'Error: no ', Matrix%Subclass, ' in Matrix_Class.'
    end select

  end subroutine Finalize_Matrix

end module Matrix_Class

Note that this set of m4 macros depends on the m4 commands in the settings.m4 file and on the SUPERCLASS and SUBCLASSES macro definitions.

m4 macros defined in the include/superclass.m4 file:

 SUPERCLASS_ARGUMENTS  Used internally by the SUPERCLASS_ROUTINE and SUPERCLASS_FUNCTION macros.
 SUPERCLASS_DECLARATIONS  Used internally by the SUPERCLASS_ROUTINE and SUPERCLASS_FUNCTION macros.
 SUPERCLASS_FUNCTION  Expands into a complete function for the superclass. This function dynamically dispatches calls to the superclass to the correct subclass function.
 SUPERCLASS_ROUTINE  Expands into a complete subroutine for the superclass. This subroutine dynamically dispatches calls to the superclass to the correct subclass routine.
 SUPERCLASS_TYPE  Outputs a standard superclass type definition.
 SUPERCLASS_USE_ASSOCIATIONS  Outputs the correct use associations for the superclass.

The Superclass m4 Macros code listing contains additional documentation.

Michael L. Hall