Search code examples
fortrangfortran

How to define correctly arithmetic operator overloading for user defined complex number in fortran?


My IDE is: Code::Blocks 20.03 ( MinGW 9.2.0 )

This is my simple code:

module mod_kompleks

  use, intrinsic :: iso_c_binding, only : rp => c_double

  implicit none

  type, public :: kom_bro

    private

    real(rp) :: dio_rea
    real(rp) :: dio_img

    contains

      procedure, private :: kom_bro_sab    ! 16 line

      generic, public :: operator(+) => kom_bro_sab  ! 18 line

  end type kom_bro

  interface kom_bro

    module procedure :: kom_bro_set

  end interface kom_bro

  contains

  ! procedure - kom_bro_set

    type(kom_bro) function kom_bro_set(rea_part, img_part) result(bro_c)

      real, intent(in) :: rea_part, img_part

      bro_c%dio_rea = rea_part
      bro_c%dio_img = img_part

    end function kom_bro_set

  ! procedure - kom_bro_sab

    function kom_bro_sab(bro_a, bro_b) result(bro_c)

      type(kom_bro), intent(in) :: bro_a
      type(kom_bro), intent(in) :: bro_b
      type(kom_bro)             :: bro_c

      bro_c%dio_rea = bro_a%dio_rea + bro_b%dio_rea
      bro_c%dio_img = bro_a%dio_img + bro_b%dio_img

    end function kom_bro_sab

end module mod_kompleks

program kompleksni_broj

  use, non_intrinsic :: mod_kompleks

  implicit none

  integer :: i

  type(kom_bro) :: broj_01(3)
  type(kom_bro) :: broj_02(3)
  type(kom_bro) :: broj_03(3)

  do i = 1, 3

    broj_01(i) = kom_bro(i + 2.2,i + 3.3)
    broj_02(i) = kom_bro(i + 4.4,i + 5.5)

    broj_03(i) = broj_01(i) + broj_02(i)

  end do

end program kompleksni_broj

I intend to define a user type that would look like a complex number but would also allow the arithmetic operation of adding two complex numbers. Since I am not experienced in the programming language Fortran in my example I came across a problem where the compiler reports the following errors to me:

|16|Error: Non-polymorphic passed-object dummy argument of 'kom_bro_sab' |18|Error: Undefined specific binding 'kom_bro_sab' as target of GENERIC '+' ||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

My knowledge of OOP in the programming language Fortran is not enough for me to be able to solve this problem on my own. Is it even possible to define such a user-defined type?


Solution

  • You have multiple errors. Most important the operator overloading is wrong. See my example implementation below.

    Derived data type for complex numbers (file name b.f90)

    module mod_kompleks
      use, intrinsic :: iso_c_binding, only : rp => c_double
      implicit none
    
      private
      public kom_bro
      public operator(+)
    
      type kom_bro
        private
        real(rp) :: dio_rea
        real(rp) :: dio_img
      contains
        procedure :: init  => kom_bro_init
        procedure :: print => kom_bro_print
      end type
    
      interface operator(+)
        module procedure kom_bro_sab
      end interface
    
      interface kom_bro
        module procedure kom_bro_init2
      end interface
    contains
      function kom_bro_init2(rea_part, img_part) result(bro)
        real(rp), intent(in) :: rea_part
        real(rp), intent(in) :: img_part
        type(kom_bro)        :: bro
    
        call bro%init(rea_part, img_part)
      end function
    
      subroutine kom_bro_init(this, rea_part, img_part)
        class(kom_bro), intent(out) :: this
        real(rp),       intent(in)  :: rea_part
        real(rp),       intent(in)  :: img_part
    
        this%dio_rea = rea_part
        this%dio_img = img_part
      end subroutine
    
      subroutine kom_bro_print(this)
        class(kom_bro), intent(in) :: this
    
        print *, this%dio_rea, this%dio_img
      end subroutine
    
      function kom_bro_sab(bro_a, bro_b) result(bro_c)
        type(kom_bro), intent(in) :: bro_a
        type(kom_bro), intent(in) :: bro_b
        type(kom_bro)             :: bro_c
    
        bro_c%dio_rea = bro_a%dio_rea + bro_b%dio_rea
        bro_c%dio_img = bro_a%dio_img + bro_b%dio_img
      end function
    end module
    

    Program (file name a.f90)

    program kompleksni_broj
      use mod_kompleks
      use, intrinsic :: iso_c_binding, only : rp => c_double
    
      implicit none
    
      integer       :: i
      type(kom_bro) :: broj_01(3), broj_02(3), broj_03(3)
    
      do i = 1, 3
        call broj_01(i)%init(i + 2.2_rp, i + 3.3_rp)      ! initialization via type-bound routine
        broj_02(i) = kom_bro(i + 4.4_rp, i + 5.5_rp)      ! initialization via interface kom_bro aka "type constructor"
    
        broj_03(i) = broj_01(i) + broj_02(i)
        call broj_03(i)%print()
      end do
    
    end program
    

    Output

    $ gfortran -g3 -Wall -fcheck=all b.f90 a.f90 && ./a.out
       3.2000000000000002        5.4000000000000004        8.6000000000000014     
       4.2000000000000002        6.4000000000000004        10.600000000000001     
       5.2000000000000002        7.4000000000000004        12.600000000000001