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