Ok, I tried to implement what I described, and this is a little toy example:
module lib
implicit none
type base ! base type to be extended by the user of this library.
end type base
interface
subroutine work( a, b )
import :: base
class(base), intent(inout) :: a
integer, intent(inout) :: b
end subroutine work
end interface
contains
subroutine lib_sub( callback, a, b )
implicit none
procedure(work) :: callback
class(base), intent(inout) :: a
integer, intent(inout) :: b
print*, 'lib_sub entry: b=', b
call callback( a, b )
print*, 'lib_sub return: b=', b
return
end subroutine lib_sub
end module lib
program classx
use lib
implicit none
type, extends(base) :: ext_t
integer :: c
end type ext_t
type(ext_t) :: a = ext_t( c=3 )
integer :: b = 42
print*, 'initial a%c=', a%c, ' b=', b
call lib_sub( mywork, a, b )
print*, 'after lib_sub: a%c=', a%c, ' b=', b
contains
subroutine mywork( a, b )
class(base), intent(inout) :: a
integer, intent(inout) :: b
print*, 'mywork:'
select type (a)
type is (ext_t)
a%c = a%c + 1
b = b + 1
end select
return
end subroutine mywork
end program classx
$ gfortran classx.f90 && a.out
initial a%c= 3 b= 42
lib_sub entry: b= 42
mywork:
lib_sub return: b= 43
after lib_sub: a%c= 4 b= 43
In this case, the lib module defines a base type with no components. It contains a subroutine that declares a dummy argument of that type but does not access anything within it, the contents are anonymous, it only passes it on to the dummy procedure argument.
In the main program, the type is extended with useful stuff, and that extended type is passed along with the contained subroutine to the library subroutine. The mywork() subprogram does know all about the extended type, so it can modify the members of the derived type as necessary.
I think this accomplishes the same kind of thing as the void* argument in C. It allows the derived type to be passed through lib_sub() without lib_sub() knowing its contents, but it allows full access to its contents within the callback routine.
If I had more time, maybe the code could be simplified a little. I find this kind of object oriented programming in fortran clumsy. For example, I would like to just declare
type(ext_t) :: a
within mywork(), because that is the only type of argument that I ever want to pass to that routine, but I don’t think you can do that. If you could, then argument mismatches could be detected at compile time instead of run time. You must instead declare it as class(base) and then do select type within. The programmer can test for unsupported derived types at run time (I didn’t do that in the above code).
Anyway, this shows how to pass anonymous information through lib_sub() in fortran.