Home > OS >  Fortran TYPE inheritance on runtime (declared by user)
Fortran TYPE inheritance on runtime (declared by user)

Time:07-17

I want to know if it's possible (and if so how) to have a Fortran TYPE inherit another TYPE on runtime. For example the user provides an input file that states which TYPE needs to be inherited. Below is an example,

MODULE A_MOD
  type A
    real(8) :: m, n 
  end type
END MODULE

And similarly for B_MOD

MODULE B_MOD
  type B
    real(8) :: param 
  end type
END MODULE

Both A and B also have procedures and other elements defined in the modules. I now have another TYPE C and I want it to inherit either A or B depending on a user input. As a general idea,

input = A ! provided by user
...
type, extends(input) :: C
  end type

I can do something similar to this in Python. I'm not very familiar yet with Fortran polymorphism so any help would be appreciated !

CodePudding user response:

No, this is not possible. The compiler needs to know the memory requirements of a type at compile time, so runtime type definitions are not possible.

A possible workaround would be to define two C types, CA and CB, and then use a factory method to pick which type to use at runtime.

Code for this might look something like:

module m
  type, abstract :: Base
  contains
    procedure(hi_Base), deferred :: hi
  end type

  abstract interface
    subroutine hi_Base(self)
      import :: Base
      class(Base), intent(in) :: self
    end subroutine
  end interface

  type, extends(Base) :: A
  contains
    procedure :: hi => hi_A
  end type

  type, extends(Base) :: B
  contains
    procedure :: hi => hi_B
  end type

  type, extends(A) :: CA
  end type

  type, extends(B) :: CB
  end type
contains
  subroutine  hi_A(self)
    class(A), intent(in) :: self
    write(*,*) "Hi, I'm an A!"
  end subroutine

  subroutine  hi_B(self)
    class(B), intent(in) :: self
    write(*,*) "Hi, I'm a B!"
  end subroutine

  function factory(switch) result(output)
    logical, intent(in) :: switch
    class(Base), allocatable :: output

    if (switch) then
      output = CA()
    else
      output = CB()
    endif
  end function
end module

program p
  use m
  implicit none

  class(Base), allocatable :: foo

  foo = factory(.true.)
  call foo%hi()

  foo = factory(.false.)
  call foo%hi()
end program

Having said that, you might have better luck if C has an A or a B instead of inheriting from an A or a B. This would look something like

module m
  type, abstract :: Base
  contains
    procedure(hi_Base), deferred :: hi
  end type

  abstract interface
    subroutine hi_Base(self)
      import :: Base
      class(Base), intent(in) :: self
    end subroutine
  end interface

  type, extends(Base) :: A
  contains
    procedure :: hi => hi_A
  end type

  type, extends(Base) :: B
  contains
    procedure :: hi => hi_B
  end type

  type :: C
    class(Base), allocatable :: foo
  end type

  interface C
    module procedure new_C
  end interface
contains
  subroutine  hi_A(self)
    class(A), intent(in) :: self
    write(*,*) "Hi, I'm an A!"
  end subroutine

  subroutine  hi_B(self)
    class(B), intent(in) :: self
    write(*,*) "Hi, I'm a B!"
  end subroutine

  function new_C(switch) result(self)
    logical, intent(in) :: switch
    type(C) :: self

    if (switch) then
      self%foo = A()
    else
      self%foo = B()
    endif
  end function
end module

program p
  use m
  implicit none

  type(C) :: bar

  bar = C(.true.)
  call bar%foo%hi()

  bar = C(.false.)
  call bar%foo%hi()
end program
  • Related