Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28456 Discussions

OOP fortran: can not make a subroutine execute different objects

luis_gc_rego
Beginner
316 Views

I need some help please.
In this code I create two objects (MM and FF) that extend an abstract
object (MF). Then I have a subroutine (execute_MM_or_FF) that is
supposed to handle both objects (MM and FF).
I tried several ways of doing it but none worked; this is an example
for which I get the error message
error #8169: The specified interface is not declared.   [OUTPUT]
What is the problem with this code? thanks

!===================================
module Abstract_class_m

    implicit none
    private

    type , abstract , public :: MF
    contains
        procedure (output_info) , deferred :: output
    end type

    abstract interface

        subroutine output_info( me , iter)
            import :: MF
            class(MF) , intent(in) :: me
            Integer   , intent(in) :: iter
        end subroutine

    end interface

end module Abstract_class_m
!===================================
module MM_class_m

    use Abstract_class_m 

    implicit none

    private

    public :: MM

    type,extends(MF):: MM
        integer                  :: ITMAX = 200        
        character (len=2)       :: driver
    contains
        procedure :: output => output_MM
    end type MM

    interface MM
        module procedure  constructor
    end interface

contains

function constructor( ) result( me )
implicit none

type(MM) :: me

me % driver = "MM"

end function constructor
!
!
subroutine output_MM( me , iter)
implicit none
class(MM)   , intent(in) :: me
integer     , intent(in) :: iter

print*, me%driver , iter

end subroutine output_MM

end module MM_class_m
!===================================
module FF_class_m

    use Abstract_class_m 

    implicit none

    private

    public :: FF

    type,extends(MF):: FF
        integer                  :: ITMAX = 20        
        character (len=2)       :: driver
    contains
        procedure :: output => output_FF
    end type FF

    interface FF
        module procedure  constructor
    end interface

contains

function constructor( ) result( me )
implicit none

type(FF) :: me

me % driver = "FF"

end function constructor
!
!
subroutine output_FF( me , iter)
implicit none
class(FF)   , intent(in) :: me
integer     , intent(in) :: iter

print*, me%driver , iter

end subroutine output_FF

end module FF_class_m
!===================================
module execute_MM_or_FF

        use MM_class_m          , only: MM
        use FF_class_m          , only: FF
        use Abstract_class_m    , only: MF

        implicit none

        public :: execute

        private

        type, extends(MF) :: OBJ
            integer          :: ITMAX
            character(len=2) :: driver
        contains
            procedure :: output
        end type

contains     

subroutine execute( me , n )
class(OBJ) , intent(inout) :: me
integer    , intent(in)    :: n

    print*, me%itmax
    call me%output(n)

end subroutine execute

end module execute_MM_or_FF
!===================================

program test

use MM_class_m              , only: MM
use FF_class_m                , only: FF
use execute_MM_or_FF   , only: execute

implicit none

character(2) :: driver = "MM"
integer      :: iter = 3

type(MM) :: a
type(FF) :: b

if(driver == "MM") then
    a = MM()
    call execute(a,iter)
else
    b = FF()
    call execute(b,iter)
end if

end program test

0 Kudos
4 Replies
IanH
Honored Contributor II
316 Views

The error arises because the `OBJ` type in the `execute_MM_or_FF module` declares a binding called `output`.  There is no procedure named `output` in that module to implement that binding.  I'm not sure what your intent was here - if you wanted to override that binding in the OBJ type then you need to provide the procedure, if you just wanted the binding to continue to refer to the procedure that the binding references in the parent type, then you do not redeclare it in the extension.

I note that in your main program you are using a CALL statement to invoke `execute_MM_or_FF` - that is - you are trying to call a module.  You cannot do that.  The thing being invoked by a CALL statement needs to be a subroutine.

0 Kudos
luis_gc_rego
Beginner
316 Views

My apologies, the  CALL statement to invoke `execute_MM_or_FF´ was a mistake. It has been corrected in the example program.

Anyway, my intention is to call ´execute´ having either ´a´ or ´b´ as an argument, whereas the subroutine ´execute´ in module ´execute_MM_or_FF´ handles either objects through the class OBJ that has the same parent as MM and MF

I have tried to implement this code through various different constructions. I also understand that the procedure ´output´ of OBJ should be implemented, but I actually want to inherit ouput from either MM or FF depending on the type of argument ´me´ that is passed to ´execute´.

 

0 Kudos
IanH
Honored Contributor II
316 Views

Fortran does not support multiple inheritance, if that is what you are trying to do.

`execute` currently takes an object of type OBJ.  It can't take an object of declared type MM or FF, they are not extensions of OBJ.

Your MM, FF and OBJ types all have the same components.  Is it really necessary that they be separate types?  Could you have another type, that was an extension of MF and that acted as the parent of the other types, that had those common components?  If so, execute just takes an object of that type, and then just calls the output binding.

If not - you need to explain what you are trying to achieve.

module Abstract_class_m
  implicit none
  private
  
  type , abstract , public :: MF
  contains
    procedure (output_info) , deferred :: output
  end type
  
  abstract interface
    subroutine output_info( me , iter)
      import :: MF
      implicit none
      class(MF) , intent(in) :: me
      Integer   , intent(in) :: iter
    end subroutine
  end interface
  
  type, extends(MF), abstract, public :: MF_intermediate
    integer                  :: ITMAX
    character (len=2)       :: driver
  end type MF_intermediate
end module Abstract_class_m

module MM_class_m
  use Abstract_class_m
  implicit none
  private
  public :: MM
  
  type, extends(MF_intermediate) :: MM
  contains
    procedure :: output => output_MM
  end type MM
  
  interface MM
    module procedure  constructor
  end interface
contains
  function constructor( ) result( me )
    type(MM) :: me
    
    me % ITMAX = 200
    me % driver = "MM"
  end function constructor
  
  subroutine output_MM(me , iter)
    class(MM)   , intent(in) :: me
    integer     , intent(in) :: iter
    print*, me%driver , iter
  end subroutine output_MM
end module MM_class_m

module FF_class_m
  use Abstract_class_m
  implicit none
  private
  public :: FF
  
  type,extends(MF_intermediate):: FF
  contains
    procedure :: output => output_FF
  end type FF
  
  interface FF
    module procedure  constructor
  end interface
contains
  function constructor( ) result( me )
    type(FF) :: me
    
    me % driver = "FF"
    me % ITMAX = 20
  end function constructor
  
  subroutine output_FF(me , iter)
    class(FF)   , intent(in) :: me
    integer     , intent(in) :: iter
    
    print*, me%driver , iter
  end subroutine output_FF
end module FF_class_m

module execute_MM_or_FF
  use MM_class_m          , only: MM
  use FF_class_m          , only: FF
  use Abstract_class_m    , only: MF_intermediate
  implicit none
  public :: execute
  private

contains
  subroutine execute(me , n)
    class(MF_intermediate) , intent(inout) :: me
    integer    , intent(in)    :: n
    
    print*, me%itmax
    call me%output(n)
  end subroutine execute
end module execute_MM_or_FF

program test
  use FF_class_m , only: FF
  use MM_class_m , only: MM
  use execute_MM_or_FF
  character(2) :: driver = "MM"
  integer      :: iter = 3
  type(MM) :: a
  type(FF) :: b

  if(driver == "MM") then
    a = MM()
    call execute(a,iter)
  else
    b = FF()
    call execute(b,iter)
  end if
end program test

 

0 Kudos
luis_gc_rego
Beginner
316 Views

Perhaps this is not multiple inheritance, but I finally managed a way to do what I want in the code below.

!===================================
module Parent_class_m

    implicit none
    private

    type , public :: MF
        integer                 :: ITMAX = 100
        character (len=2)       :: driver_abs
    contains
        procedure :: output
    end type

    contains

    subroutine output( me , iter)
            class(MF) , intent(in) :: me
            Integer   , intent(in) :: iter
    end subroutine

end module Parent_class_m
!===================================
module MM_class_m

    use Parent_class_m

    implicit none

    private

    public :: MM

    type,extends(MF):: MM
        integer                 :: ITMAX_MM = 200
        character (len=2)       :: driver
    contains
        procedure :: output => output_MM
    end type MM

    interface MM
        module procedure  constructor
    end interface

contains

function constructor( ) result( me )
implicit none

type(MM) :: me

me % itmax  = me % itmax_MM
me % driver = "MM"

end function constructor
!
!
subroutine output_MM( me , iter)
implicit none
class(MM)   , intent(in) :: me
integer     , intent(in) :: iter

print*, me%driver , iter

end subroutine output_MM

end module MM_class_m
!===================================
module FF_class_m

    use Parent_class_m

    implicit none

    private

    public :: FF

    type,extends(MF):: FF
        integer                 :: ITMAX_FF = 20
        character (len=2)       :: driver
    contains
        procedure :: output => output_FF
    end type FF

    interface FF
        module procedure  constructor
    end interface

contains

function constructor( ) result( me )
implicit none

type(FF) :: me

me % itmax  = me%itmax_FF
me % driver = "FF"

end function constructor
!
!
subroutine output_FF( me , iter)
implicit none
class(FF)   , intent(in) :: me
integer     , intent(in) :: iter

print*, me%driver , iter+100

end subroutine output_FF

end module FF_class_m
!===================================
module execute_MM_or_FF

        use MM_class_m          , only: MM
        use FF_class_m          , only: FF
        use Parent_class_m    , only: MF

        implicit none

        public :: execute

        private

contains

subroutine execute( me , n )
class(MF) , intent(inout) :: me
integer    , intent(in)    :: n

    print*, me%itmax
    call me%output(n)

end subroutine execute

end module execute_MM_or_FF
!===================================

program test

use MM_class_m         , only: MM
use FF_class_m         , only: FF
use execute_MM_or_FF   , only: execute
implicit none

character(2) :: driver = "MM"
integer      :: iter = 3

type(MM) :: a
type(FF) :: b

if(driver == "FF") then
    a = MM()
    call execute(a,iter)
else
    b = FF()
    call execute(b,iter)
end if

end program test

 

 

 

0 Kudos
Reply