3

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?

Biggsy
  • 1,306
  • 1
  • 12
  • 28
  • 1
    I have some sympathy for the question, but I'm not entirely sure of your aim. Why do you particularly need to have a pointer component pointing to the same thing as the bound procedure? There are times when that is useful/necessary, but why not do that "exceptionally" when required. – francescalus May 16 '18 at 10:25
  • Say I have 2 types that extend `base` called `my_extension` & `my_other_extension`. Each has 2 procedures: `my_extension_procedure_one`, `my_extension_procedure_two`, `my_other_extension_procedure_one` & `my_other_extension_procedure_two`. I want to create 4 objects of class `base` where the pointer in the 1st object points to `my_extension_procedure_one`, the pointer in the 2nd object points to `my_extension_procedure_two`, etc. I can then store these in an array of `base` objects & call `run` on each which will in effect call each of the 4 procedures once. Does that make more sense? – Biggsy May 16 '18 at 15:30
  • 1
    I think I understand that. I can't suggest a sensible approach (noting that you will indeed have the problems of your question), but before I worked hard on this I'd worry about the fact that I'm still having to set up those pointers by hand (`ptr(1)=>type1%proc1; ptr(2)=>type1%proc2; ptr(3)=>type2%proc1; ptr(4)=>type2%proc2`) so perhaps that array won't save me much. – francescalus May 16 '18 at 15:42
  • That is true. But... a) It's all in one place instead of having a type extension per procedure; b) In the case of a type extension per procedure, one still needs to construct an array of those; and (most importantly) c) I intend to write a fortran source code preprocessor in some other language that can automatically generate the list of pointers and write them to a fortran source file (so a clean solution will simplify the implementation of the preprocessor). – Biggsy May 16 '18 at 19:24
  • 1
    What is the point of the `my_procedure` binding in the extension? Does the `my_procedure` procedure need to be bound to that type? – IanH May 16 '18 at 20:05
  • Good point. I've given it some thought but unfortunately, yes, the procedures in `my_extension` need to be type-bound. This is because they will call other type-bound procedures in `base` that alter the state of components of `base`. If `my_extension_procedure_one` etc are not type-bound, then the `base` objects would have to be passed in which negatively affects the API of `my_extension_procedure_one` etc worse than the original problem of `my_extension` etc having to be abstract. – Biggsy May 17 '18 at 08:01
  • 1
    Note that using file extension .f08 is not recommended and some compilers will reject it without special options https://stackoverflow.com/questions/20269076/correct-suffix-for-fortran-2003-source-file-intel-fortran-compiler Will you rename all your files as soon as you add some Fortran 2015 feature? – Vladimir F Героям слава May 17 '18 at 09:25
  • OK, thanks, good tip. I have updated the question and I will update my files. – Biggsy May 17 '18 at 10:10
  • 2
    Your explanation for why the procedure needs to be bound to a type does not make sense to me. Being bound to a type does not make a procedure special in terms of what it can or cannot do ("because they will call..."). Bindings are all about dynamic dispatch (which procedure is invoked at runtime when a binding is referenced) and namespace management. – IanH May 17 '18 at 10:40
  • It is true that in terms of dynamic dispatch it is not necessary for them to be type-bound procedures. That's why I though about making them not type-bound as suggested. However, in that case one has to pass the objects of type `base` into `my_extension_procedure_one` etc so that their state can be modified. This makes for a messy API as users don't want to have to write procedures that receive a `base` object. I'd say there's more to object-oriented programming than just dynamic dispatch - it's also about encapsulation which is what I'm trying to do here. – Biggsy May 17 '18 at 14:46
  • No, for dynamic dispatch to happen it HAS TO BE called as a type-bound procedure! Otherwise you call the subroutine you call and there is nothing dynamic in sight. – Vladimir F Героям слава May 23 '18 at 15:33

0 Answers0