In How to pass subroutine names as arguments in Fortran? we learned how to pass subroutine names as arguments in Fortran. How can we do this inside a class structure?
The ensuing code produces the following compilation error using GNU Fortran (GCC) 5.1.0:
gfortran -Wall -Wextra -Wconversion -Og -pedantic -fcheck=bounds -fmax-errors=5 class_pass.f08
myClass.f08:44:30:
class ( test ), target :: me
1
Error: Derived type ‘test’ at (1) is being used before it is defined
myClass.f08:9:21:
procedure, public :: action => action_sub
1
Error: Non-polymorphic passed-object dummy argument of ‘action_sub’ at (1)
myClass.f08:40:36:
class ( test ), target :: me
1
Error: CLASS variable ‘me’ at (1) must be dummy, allocatable or pointer
(null):0: confused by earlier errors, bailing out
The main routine follows. It includes a routine check
used as a diagnostic.
include 'myClass.f08'
program class_pass
use myClass
implicit none
type ( test ) :: myTest
call myTest % check ()
call myTest % action ( square_sub )
end program class_pass
The module:
module myClass
implicit none
type :: test
real :: x, y
contains
private
procedure, public :: action => action_sub
procedure, public :: square => square_sub
procedure, public :: double => double_sub
procedure, public :: check => check_sub
end type test
private :: action_sub
private :: square_sub
private :: double_sub
private :: check_sub
contains
subroutine square_sub ( me )
class ( test ), target :: me
me % y = me % x ** 2
end subroutine square_sub
subroutine double_sub ( me )
class ( test ), target :: me
me % y = me % x * 2
end subroutine double_sub
subroutine check_sub ( me )
class ( test ), target :: me
me % x = 5.0
call double_sub ( me )
print *, 'x = ', me % x, ', y = ', me % y
end subroutine check_sub
subroutine action_sub ( sub )
class ( test ), target :: me
interface mySub
subroutine sub ( me )
class ( test ), target :: me
end subroutine sub
end interface mySub
call sub ( me )
print *, 'x = ', me % x, ', y = ', me % y
end subroutine action_sub
end module myClass
Many thanks to @Vladimir F for the original solution and tips.
Your errors are due to missing parameters in your procedure action_sub
and a few other minor things. This procedure is bound to your derived type via
procedure, public :: action => action_sub
and by default the polymorphic class variable is passed as the first argument to action_sub
. You have correctly accounted for this in your other type bound procedures, but are missing it in this procedure. You also need to import the derived type in the interface block within action_sub
in order to use the type there. This modified version of just that procedure allows your module to compile properly:
subroutine action_sub ( me, sub )
class ( test ), target :: me
interface mySub
subroutine sub ( me )
import test
class ( test ), target :: me
end subroutine sub
end interface mySub
call sub ( me )
print *, 'x = ', me % x, ', y = ', me % y
end subroutine action_sub
next, in your main program where you do:
call myTest % action ( square_sub )
in order to reference square_sub
here you need to make the procedure public in your module. Once you remove the private
attribute from the module procedure your code compiles and runs:
x = 5.00000000 , y = 10.0000000
x = 5.00000000 , y = 25.0000000