Overloading a subroutine means to redefine its internal functionality for a customized behavior. Overall it adapts the class new characteristics to already wide-spread Fortran functionalities (==, =, + ,-, …). Specifically, this post only focus on assignment (=).

In the following example, Mynumber is generic class to hold any type of real number. For that reason, it seems interesting enough to be able to directly set or get its data.

The main program exemplifies what is meant to do in a clean way:

main program
  implicit none

  type(mynumber) :: cnum
  real :: scalar
  real :: arr(24)
  real, allocatable :: found(:)

  ! initialization
  cnum = mynumber(24.1)
  arr=123.2

  ! assignment
  cnum = arr
  cnum = 0.0
  cnum = cnum2

  ! reversed assignment
  found = cnum
end program

4 types of assignment can be found above:

  1. mynumber = mynumber
  2. mynumber = scalar number
  3. mynumber = array
  4. array = mynumber

Regarding the 4 cases, the last one is the most interesting to me. It is a reverse copy/assignment. It gets its internal values in a simple way.

When writing the code, you should make sure to properly define the subroutines headers. Those must follow Fortran standards. In any case, the compiler will complain if it is not the case.

Its current implementation for each type of assignment:

module
  use precision_mod, only: sp

  implicit none

  type mynumber
    ...
  contains
    !< copy/assignment
    procedure :: copy_mynumber !< mynumber = mynumber, 1st case
    procedure :: copy_scalar_rsp !< mynumber = 25.0, 2nd case
    procedure :: copy_array_to_raw_rsp_1 !< mynumber = realarray(:), 3rd case
    !< reverse copy/assignment
    procedure, pass(self) :: copy_raw_rsp_1_to_array !< realarray(:) = mynumber, 4th case

    !< overload assignment
    generic, public :: assignment(=) => copy_mynumber, &
                       copy_scalar_rsp, copy_array_rsp_1, &
                       copy_raw_rsp_1_to_array
  end type mynumber
contains
  ! copy
  pure subroutine copy_scalar_rsp(self, other)
      !< 2nd case
      class(mynumber), intent(inout) :: self
      real(kind=sp), intent(in) :: other
      ...
  end subroutine copy_scalar_rsp

  pure subroutine copy_raw_rsp_1_to_array(other, self)
    !< 4th case
    real(kind=sp), allocatable, intent(inout) :: other(:)
    class(mynumber), intent(in) :: self
    ...
  end subroutine copy_raw_rsp_1_to_array

  pure subroutine copy_array_to_raw_rsp_1(self, other)
    !< 3rd case
    class(mynumber), intent(inout) :: self
    real(kind=sp), intent(in) :: other(:)
    ...
  end subroutine copy_array_to_raw_rsp_1

  pure subroutine copy_array(self, other)
      !< 1st case
      class(mynumber), intent(inout) :: self
      class(mynumber), intent(in) :: other

      ...
  end subroutine copy_array

end module mynumber_mod

copy_array_to_raw_rsp_1 should be extended for each rank/kind/type you might want to support. Because it’s a boring task, it is better to let fypp (or any other pre-processor) do the job for you. So it generates the remaining code. But this is another story 😀

Leave a Reply

Your email address will not be published. Required fields are marked *