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?

0

There are 0 answers