I have checked similar questions and relevant textbooks but cannot find a solution to this problem.
NB: This is using modern Fortran.
So, I want to have a base type, e.g. base
, that contains a type-bound procedure, e.g. run
, that delegates to a subroutine in types that extend base, e.g. type, extends(base) :: my_extension
. Let's call the subroutine to which we wish to delegate my_procedure
.
I can achieve this in a rather convoluted way by making base
abstract, making base
contain a deferred procedure, e.g. delegate
, getting run
to delegate to delegate
, then implementing delegate
in my_extension
and getting it to delegate to my_procedure
.
However, this is messy as it requires types that extend base
to implement delegate
but all implementations simply delegate to some other procedure. This is further complicated by the fact that I usually want multiple instances of my_extension
where each instance delegates to a different procedure within my_extension
, in which case I need to keep my_extension
abstract, extend my_extension
and implement delegate
there so I end up with as many extensions as I have procedures!
So, I'm wondering if there is a cleaner way using procedure pointers or similar. What I want is something like this...
base.f90:
module base_mod
implicit none
type base
procedure(my_interface), pointer :: ptr ! Pointer component
contains
procedure :: run ! Type-bound procedure
end type base
abstract interface
subroutine my_interface(self)
import :: base
class(base) :: self ! This is a problem...
end subroutine my_interface
end interface
contains
subroutine run(self)
class(base) :: self
call self%ptr()
end subroutine run
end module base_mod
my_extension.f90:
module my_extension_mod
use base_mod
implicit none
type, extends(base) :: my_extension
contains
procedure :: my_procedure
end type my_extension
contains
subroutine my_procedure(self)
class(my_extension) :: self ! ...because this is different.
! Do useful stuff, e.g.
print *, "my_procedure was run"
end subroutine my_procedure
end module my_extension_mod
main.f90:
program main
use my_extension_mod
implicit none
type(my_extension) :: my_instance
procedure(my_interface), pointer :: my_ptr
my_ptr => my_procedure
my_instance = my_extension(my_ptr) ! Use implicit constructor
call my_instance%run() ! Expect to see "my_procedure was run" printed
end program main
make.sh:
#! /bin/bash
gfortran -c base.f90
gfortran -c my_extension.f90
gfortran base.o my_extension.o main.f90
However, the compiler complains as follows:
main.f90:9.14:
my_ptr => my_procedure
1
Error: Interface mismatch in procedure pointer assignment at (1): Type/rank mismatch in argument 'self'
This is because my_interface
expects an object of class base
as input, whereas my_procedure
has an object of class my_extension
as input so technically the interfaces don't match. However, my_extension
extends base
so, in a way, this should be OK (but obviously is not OK as far as the compiler is concerned).
So, my question is: How can I get past this problem? How can I have an interface that works for my_procedure
but still works for other procedures in other types that extend base
(e.g. those in my_other_extension
)? Or how can I have pointers to procedures in extensions of base
without using an interface? Or how can I achieve what I'm trying to do some other way (e.g. without using pointers) but still avoiding the messy abstract type method described at the top?