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:
- mynumber = mynumber
- mynumber = scalar number
- mynumber = array
- 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 😀