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