Is it possible in Fortran to assign procedure name at run time in a type bound procedure? - pointers

I discovered type-bound procedures and was wondering how I could use them. I have this code which is working as expected:
module utils
implicit none
type TypeParam
integer :: val
contains
procedure :: initval => initI
procedure :: writeval => writeI
end type TypeParam
contains
!---------------------------
subroutine initI(this,val)
class(TypeParam),intent(inout)::this
integer,intent(in) :: val
this%val=val
end subroutine initI
!---------------------------
subroutine writeI(this)
class(TypeParam),intent(inout)::this
print*,this%val
end subroutine writeI
!---------------------------
end module utils
program testtypebound
use utils
implicit none
type(TypeParam) :: TP(2)
call TP(1)%initval(3)
call TP(2)%initval(5)
call TP(1)%writeval() ! Returns 3
call TP(2)%writeval() ! Returns 5
end program testtypebound
Now I do not know how, if it makes any sense at all, to assign initval and writeval at runtime. Having them point to null() and assign them in the main program as TP(1)%initval=>othersubroutine.
The following code, which does not use type-bound procedure, does what I want, not sure though if it the way to go. Are there any pitfalls to the second approach ?
Many thanks
module utils
implicit none
type TypeParam
integer :: val
procedure(InitValInteger), pointer :: initval => null()
procedure(WriteValInteger), pointer :: writeval => null()
end type TypeParam
interface
subroutine InitValInteger(this,val)
import TypeParam
class(TypeParam),intent(inout)::this
integer,intent(in) :: val
end subroutine InitValInteger
subroutine WriteValInteger(this)
import TypeParam
class(TypeParam),intent(inout)::this
end subroutine WriteValInteger
end interface
contains
!---------------------------
subroutine initI(this,val)
class(TypeParam),intent(inout)::this
integer,intent(in) :: val
this%val=val
end subroutine initI
!---------------------------
subroutine writeI(this)
class(TypeParam),intent(inout)::this
print*,this%val
end subroutine writeI
!---------------------------
end module utils
program testtypebound
use utils
implicit none
type(TypeParam) :: TP(2)
TP(1)%initval =>initI
TP(1)%writeval=>writeI
TP(2)%initval =>initI
TP(2)%writeval=>writeI
call TP(1)%initval(3)
call TP(2)%initval(5)
call TP(1)%writeval() ! Returns 3
call TP(2)%writeval() ! Returns 5
end program testtypebound
Clarification
As pointed out in the comments, the previous examples may not be useful. Here is a code which I think does what I want and could be extended to my real code:
module utils
implicit none
type TypeParam
integer :: val
procedure(UseValue), pointer :: useval => null()
end type TypeParam
interface
real*8 function UseValue(this,i)
import TypeParam
class(TypeParam),intent(inout)::this
integer,intent(in) :: i
end function UseValue
end interface
contains
!---------------------------
real*8 function useval1(this,i)
class(TypeParam),intent(inout)::this
integer,intent(in) :: i
useval1=this%val+i
end function useval1
!---------------------------
real*8 function useval2(this,i)
class(TypeParam),intent(inout)::this
integer,intent(in) :: i
useval2=this%val**2+i
end function useval2
!---------------------------
end module utils
program testtypebound
use utils
implicit none
integer :: i
type(TypeParam) :: TP
write(*,*) "Enter version 1 or 2"
read(*,*) i
if(i==1)then
TP%val=2
TP%useval =>useval1
elseif(i==2)then
TP%val=1
TP%useval =>useval2
else
write(*,*) "Version unknown (1 or 2)"
stop
endif
print*, TP%useval(2) ! Returns 4 if i=1 and 3 if i=2
end program testtypebound
But before I start to implement this, does this code have drawbacks, flaws? Can it be made simpler/more compact using type-bound procedures ? In real life, TP will be an array, such that each component of the array will hold different procedures depending on user input.

Type-bound procedures are "bound to a derived type and referenced via an object of that type" (Fortran 2018, 3.112.6). Being bound to a type and not an object means that two objects of the same type result in the same reference. (Further, the definition of a type cannot change during execution.)
A procedure pointer component is different: it's a component of the type and each object instance of the type can have its own value and, for a variable, its value can change during execution.
Which mechanism best suits a use case depends on what is required. If you want two objects of the same type to resolve to different procedure references, or want the referenced procedure to vary during execution, you'll be using procedure pointer components.
A procedure pointer can be not-associated and there's no equivalent state for a type-bound procedure. This means you have a responsibility to ensure that call a%s() has the s procedure pointer component pointer associated with a target, but also allows you to do logic like if (ASSOCIATED(a%s)) ... (if it's of defined association status). You're also responsible for ensuring it always points to the place you want it to point (note also that one can't PROTECT components) and for ease you may well end up writing a structure constructor.
Equally, a procedure pointer component can be used in ways a binding name cannot be: call run(a%s) is allowed for a procedure pointer component, but not for a type-bound procedure.
That said, the use case of referencing based on a run-time condition can be addressed even using type-bound procedures:
type t
logical :: use_a = .TRUE.
contains
procedure :: selector
end type t
where selector is a wrapper like
subroutine selector(this, val)
class(t), intent(in) :: this
integer, intent(in) :: val
if (this%use_a) then
call A(this, val)
else
call B(this, val)
end if
end subroutine selector

Related

Fortran Procedure Pointers to Interfaces [duplicate]

I am using procedure overloading and interfaces in order to achieve some sort of genericity in a Fortran program.
For this, I have a module which contains a number of procedures, all duplicated in order to be able to change the variable types. I also have at the beginning of the module, a series of interfaces of the type:
interface norm
module procedure &
norm_r8, &
norm_c
end interface
Now my problem is that I am trying to reference norm using a procedure pointer, as such (in a different module):
procedure(), POINTER :: pNorm => NULL()
pNorm => norm
However, in this situation, gfortran gives me an error saying that I have an undefined reference to norm. If I point to norm_r8 or norm_c, no problem. But since the part of the code that assigns the pointer is not aware of the type of the variables that will be used when norm is called, I need to point to the generic name! Is there a way to point towards an overloaded procedure?
As far as I can tell, a procedure pointer is not allowed to point at a generic interface. The standard only mentions procedures with the EXTERNAL attribute, a module procedures, or certain intrinsic procedures may be associated with a procedure pointer (C1220, ISO/IEC 1539-1:2010). Gfortran also issues a helpful error message for your case:
Error: Procedure pointer target 'norm' at (1) must be either an intrinsic,
host or use associated, referenced or have the EXTERNAL attribute
It also makes sense that you cannot associate to an interface, but only a procedure. An interface is only used in the procedure(INTERFACE) statement to give an explicit interface to the procedures it can point at.
This shouldn't be a showstopper for you, as the purpose of a generic interface can negate your need for a pointer. As long as all potential calls the pointer would be used for are unique in type, kind, rank and number of arguments (so the compiler can differentiate between them), you can just add all of them to a single generic interface and call that in lieu of the pointer. Alternatively you could use a select type() construct to selectively associate your pointer with the specific procedure for your type to avoid needing to associate with a generic interface.
Here is an example of a wrapper procedure to assign the pointer to a specific procedure based on an argument type
subroutine get_proc_ptr(pp, arg)
implicit none
procedure(), pointer, intent(out) :: pp
class(*), intent(inout) :: arg
select type(arg)
type is (real(kind=kind(1d0)))
pp => norm_r8
type is (real)
pp => norm_r
type is (integer)
pp => norm_i
type is (complex)
pp => norm_c
class default
pp => null()
end select
end subroutine
Which can be made use of like this:
real(kind=kind(1d0)) :: arg_r8
procedure(), pointer :: pNorm => null()
arg_r8 = 4.0123456789d30
call get_proc_ptr(pNorm, arg_r8)
call pNorm(arg_r8)
Here is a complete compilable example:
module proc
implicit none
interface norm
module procedure &
norm_r8, &
norm_r, &
norm_i, &
norm_c
end interface
contains
subroutine norm_r8(arg)
implicit none
real(kind=kind(1d0)), intent(in) :: arg
write (*,*) "real8: ", arg
end subroutine
subroutine norm_r(arg)
implicit none
real, intent(in) :: arg
write (*,*) "real: ", arg
end subroutine
subroutine norm_i(arg)
implicit none
integer, intent(in) :: arg
write (*,*) "integer: ", arg
end subroutine
subroutine norm_c(arg)
implicit none
complex, intent(in) :: arg
write (*,*) "complex: ", arg
end subroutine
subroutine get_proc_ptr(pp, arg)
implicit none
procedure(), pointer, intent(out) :: pp
class(*), intent(inout) :: arg
select type(arg)
type is (real(kind=kind(1d0)))
pp => norm_r8
type is (real)
pp => norm_r
type is (integer)
pp => norm_i
type is (complex)
pp => norm_c
class default
pp => null()
end select
end subroutine
end module
program test
use proc
implicit none
real(kind=kind(1d0)) :: arg_r8
real :: arg_r
integer :: arg_i
complex :: arg_c
procedure(), pointer :: pNorm => null()
arg_r8 = 4.0123456789d30
arg_r = 12.5
arg_i = 56
arg_c = (34,3)
call get_proc_ptr(pNorm, arg_r8)
call pNorm(arg_r8)
call get_proc_ptr(pNorm, arg_r)
call pNorm(arg_r)
call get_proc_ptr(pNorm, arg_i)
call pNorm(arg_i)
call get_proc_ptr(pNorm, arg_c)
call pNorm(arg_c)
end program
And here is the output of this program:
$ ./testprocptr
real8: 4.0123456788999999E+030
real: 12.5000000
integer: 56
complex: ( 34.0000000 , 3.00000000 )
If I understand well, you want to achieve two things at one time.
First, you want to use polymorphism to let the compiler call the correct routine dependent on whether you have a different type, rank, number of arguments etcetera.
Second, you want to use procedure pointers to switch between different procedures that have the same interface.
I tried the same. I did not manage to set a pointer to an interface, but I managed to make an interface with pointers.
If you have a module like this
module some_module
! This is the abstract interface for procedure pointers.
interface
subroutine shape_1_interface(arg)
implicit none
real, intent(in) :: arg
end subroutine shape_1_interface
subroutine shape_2_interface(arg)
implicit none
integer, intent(in) :: arg
end subroutine shape_2_interface
end interface
contains
subroutine routine_shape_1_implementation_1(arg)
implicit none
real, intent(in) :: arg
write(*,*) "Arg is real",arg
write(*,*) "Implementation 1"
end subroutine routine_shape_1_implementation_1
subroutine routine_shape_2_implementation_1(arg)
implicit none
integer, intent(in) :: arg
write(*,*) "Arg is int",arg
write(*,*) "Implementation 1"
end subroutine routine_shape_2_implementation_1
subroutine routine_shape_1_implementation_2(arg)
implicit none
real, intent(in) :: arg
write(*,*) "Arg is real",arg
write(*,*) "Implementation 2"
end subroutine routine_shape_1_implementation_2
subroutine routine_shape_2_implementation_2(arg)
implicit none
integer, intent(in) :: arg
write(*,*) "Arg is int",arg
write(*,*) "Implementation 2"
end subroutine routine_shape_2_implementation_2
subroutine routine_shape_1_implementation_3(arg)
implicit none
real, intent(in) :: arg
write(*,*) "Arg is real",arg
write(*,*) "Implementation 3"
end subroutine routine_shape_1_implementation_3
subroutine routine_shape_2_implementation_3(arg)
implicit none
integer, intent(in) :: arg
write(*,*) "Arg is int",arg
write(*,*) "Implementation 3"
end subroutine routine_shape_2_implementation_3
end module some_module
then you can do in your main program:
program main
use some_module
implicit none
procedure(shape_1_interface), pointer :: routine_shape_1
procedure(shape_2_interface), pointer :: routine_shape_2
interface routine
procedure routine_shape_1
procedure routine_shape_2
end interface routine
routine_shape_1 => routine_shape_1_implementation_1
routine_shape_2 => routine_shape_2_implementation_1
call routine(4)
routine_shape_1 => routine_shape_1_implementation_2
routine_shape_2 => routine_shape_2_implementation_2
call routine(4.0)
end program main
It is a pity that when you want to set the pointers to a different implementation, you have to do that for all shapes, but the good thing is that you can just call 'routine' and you automatically get the desired function.
This is the output:
Arg is int 4
Implementation 1
Arg is real 4.00000000000000
Implementation 2

How to have one Fortran function with different type of parameters using c_ptr?

I read the section Type Casting in Callbacks of the article Fortran Best practices.
I would like to use in my program something as described in Using type(c_ptr) Pointer
But I have a problem. I give an outline of what I try to do. I hope it will be sufficient to understand. Otherwise, let me know, I will post a full example.
I have two types and I call the same subroutine with one or the other type. The first parameter of my subroutine is an integer to indicate which is the type of the second parameter (type1_t or type2_t)
type type1_t
real :: a, b
integer :: c
end type1_t
type type2_t
real :: a,e
integer :: b,c,d
end type2_t
type(type1_t) :: type1
! ... init of type1
type(type2_t) :: type2
! ... init of type2_t
call myfoo(1,c_loc(type_1))
call myfoo(2,c_loc(type_2))
But now, I have a problem with the declaration in myfoo because the declaration must be done in fortran before instructions.
I know that the following code does not work :
subroutine myfoo(i, params)
integer, intent(in) :: i
type(c_ptr), intent(in) :: params
if (i == 1) then
type(type1_t), pointer :: pars
elseif (i ==2) then
type(type2_t), pointer :: pars
endif
call c_f_pointer(params, pars)
! do some stuff with pars (there are common parts of code either the dummy args is type_1 or type_2). For example, the line above.
end subroutine myfoo
If I use a block construct, I will have a problem because the variable disappears at the end of the block.
How can I solve it using c_ptr?
A simple way to accomplish this is to put type-specific code in two separate routines in a module, and bind them using an interface, so the compiler will pick the right subroutine based on the type of the variable provided on input:
module blabla
private
public :: foo
interface foo
module procedure foo1
module procedure foo2
end interface
contains
subroutine foo1(params)
type(t1) :: params
! Do cool stuff
end subroutine foo1
subroutine foo2(params)
type(t2) :: params
! Do type-2 cool stuff here
end subroutine foo2
end module blabla

Pointers to arrays as member variables in Fortran derived type

In Fortran, it is not possible to make a member variable of a derived type a target. (I guess this has to do with the standard not specifying how a derived type is stored in memory?) However, I can have a pointer as a member variable and associate pointers with pointers. Like I do in the example below.
module DataMod
type DataType
real(8), private, dimension(:,:), pointer, contiguous :: A
real(8), private, dimension(:,:), pointer, contiguous :: B
integer :: n
contains
procedure :: alloc
procedure :: set
procedure :: print_
final :: dealloc
end type DataType
interface DataType
procedure :: NewDataType
end interface DataType
contains
function NewDataType(dimension_) result(new)
integer, intent(in) :: dimension_
type(DataType) :: new
new%n = dimension_
end function NewDataType
subroutine alloc(dataObject)
class(DataType) :: dataObject
allocate(dataObject%A(dataObject%n,dataObject%n))
allocate(dataObject%B(dataObject%n,dataObject%n))
end subroutine alloc
subroutine set(dataObject, datas, choice)
class(DataType) :: dataObject
real(8), dimension(dataObject%n,dataObject%n), intent(in) :: datas
character(len=1), intent(in) :: choice
real(8), dimension(:,:), pointer :: dataPointer
integer :: i,j
if(choice .eq. 'A') then
datapointer => dataObject%A
elseif(choice .eq. 'B') then
datapointer => dataObject%B
else
stop
endif
do j = 1,dataObject%n
do i = 1,dataObject%n
datapointer(i,j) = datas(i,j)
enddo
enddo
end subroutine set
subroutine print_(dataObject)
class(DataType), intent(in) :: dataObject
print *, 'A'
print *, dataObject%A(1:dataObject%n,1:dataObject%n)
print *
print *, 'B'
print *, dataObject%B(1:dataObject%n,1:dataObject%n)
end subroutine print_
subroutine dealloc(dataObject)
type(DataType) :: dataObject
deallocate(dataObject%A)
deallocate(dataObject%B)
end subroutine dealloc
end module DataMod
program DataTest
use DataMod, only: DataType
implicit none
real(8), dimension(2,2) :: testArray
type(DataType) :: testType
testType = DataType(2)
call testType%alloc()
testArray(1,1) = 1
testArray(2,1) = 2
testArray(1,2) = 3
testArray(2,2) = 4
call testType%set(testArray, 'A')
testArray(1,1) = 5
testArray(2,1) = 6
testArray(1,2) = 7
testArray(2,2) = 8
call testType%set(testArray, 'B')
call testType%print_()
end program DataTest
In the set routine, I use an if statement to set a pointer to decide if it should dump the incoming matrix in A or B. In the program I'm currently working on, I must decide which combination of four different matrices to multiply together and setting a pair of pointers is much nicer than writing 16 almost identical calls to dgemm.
My question is if there are any problems with this approach besides the normal dangers of dangling pointers etc. or a way to do this without pointers? The arrays should not be accessed from outside the object. Are there any performance issues?
Components in a type definition may not be declared with the TARGET attribute (beyond the missing syntax, that would be inconsistent with other concepts and rules in the current language), but if a variable of derived type has the TARGET attribute, then all of its subobjects have the TARGET attribute too. For a type definition:
type DataType
real(8), private, dimension(:,:), allocatable :: A
real(8), private, dimension(:,:), allocatable :: B
...
The procedure set could be written...
subroutine set(dataObject, datas, choice)
class(DataType), TARGET :: dataObject
real(8), dimension(dataObject%n,dataObject%n), intent(in) :: datas
character(len=1), intent(in) :: choice
real(8), dimension(:,:), pointer :: dataPointer
! require dataobject%A and ..%B to already be allocated.
if(choice .eq. 'A') then
datapointer => dataObject%A
elseif(choice .eq. 'B') then
datapointer => dataObject%B
else
stop
endif
datapointer = datas ! or some other operation.
...
(dataPointer could be declared contiguous, the allocatable arrays that it gets pointed at are always contiguous.)
An actual argument without the TARGET attribute may be associated with a dummy argument with the TARGET attribute. If this is the case, then pointers associated with the dummy argument become undefined when execution of the procedure completes. (Such pointers may also become undefined in some cases, even when the actual argument has the TARGET attribute - see F2018 15.5.2.4p8 on for details - but these cases don't apply to scalars.)
Consequently, in the general case, if a pointer to one of the components of an object of derived type needs to outlive a procedure like set above (e.g. if dataPointer was not local to set) and you can't ensure that the actual argument will always have the TARGET attribute, then the original method using pointer components may be more appropriate. The implementation in the question appears to be ok - though I would suggest making the finalizer IMPURE ELEMENTAL to make things more robust to future changes.

Procedure pointer to interfaced/overloaded procedure

I am using procedure overloading and interfaces in order to achieve some sort of genericity in a Fortran program.
For this, I have a module which contains a number of procedures, all duplicated in order to be able to change the variable types. I also have at the beginning of the module, a series of interfaces of the type:
interface norm
module procedure &
norm_r8, &
norm_c
end interface
Now my problem is that I am trying to reference norm using a procedure pointer, as such (in a different module):
procedure(), POINTER :: pNorm => NULL()
pNorm => norm
However, in this situation, gfortran gives me an error saying that I have an undefined reference to norm. If I point to norm_r8 or norm_c, no problem. But since the part of the code that assigns the pointer is not aware of the type of the variables that will be used when norm is called, I need to point to the generic name! Is there a way to point towards an overloaded procedure?
As far as I can tell, a procedure pointer is not allowed to point at a generic interface. The standard only mentions procedures with the EXTERNAL attribute, a module procedures, or certain intrinsic procedures may be associated with a procedure pointer (C1220, ISO/IEC 1539-1:2010). Gfortran also issues a helpful error message for your case:
Error: Procedure pointer target 'norm' at (1) must be either an intrinsic,
host or use associated, referenced or have the EXTERNAL attribute
It also makes sense that you cannot associate to an interface, but only a procedure. An interface is only used in the procedure(INTERFACE) statement to give an explicit interface to the procedures it can point at.
This shouldn't be a showstopper for you, as the purpose of a generic interface can negate your need for a pointer. As long as all potential calls the pointer would be used for are unique in type, kind, rank and number of arguments (so the compiler can differentiate between them), you can just add all of them to a single generic interface and call that in lieu of the pointer. Alternatively you could use a select type() construct to selectively associate your pointer with the specific procedure for your type to avoid needing to associate with a generic interface.
Here is an example of a wrapper procedure to assign the pointer to a specific procedure based on an argument type
subroutine get_proc_ptr(pp, arg)
implicit none
procedure(), pointer, intent(out) :: pp
class(*), intent(inout) :: arg
select type(arg)
type is (real(kind=kind(1d0)))
pp => norm_r8
type is (real)
pp => norm_r
type is (integer)
pp => norm_i
type is (complex)
pp => norm_c
class default
pp => null()
end select
end subroutine
Which can be made use of like this:
real(kind=kind(1d0)) :: arg_r8
procedure(), pointer :: pNorm => null()
arg_r8 = 4.0123456789d30
call get_proc_ptr(pNorm, arg_r8)
call pNorm(arg_r8)
Here is a complete compilable example:
module proc
implicit none
interface norm
module procedure &
norm_r8, &
norm_r, &
norm_i, &
norm_c
end interface
contains
subroutine norm_r8(arg)
implicit none
real(kind=kind(1d0)), intent(in) :: arg
write (*,*) "real8: ", arg
end subroutine
subroutine norm_r(arg)
implicit none
real, intent(in) :: arg
write (*,*) "real: ", arg
end subroutine
subroutine norm_i(arg)
implicit none
integer, intent(in) :: arg
write (*,*) "integer: ", arg
end subroutine
subroutine norm_c(arg)
implicit none
complex, intent(in) :: arg
write (*,*) "complex: ", arg
end subroutine
subroutine get_proc_ptr(pp, arg)
implicit none
procedure(), pointer, intent(out) :: pp
class(*), intent(inout) :: arg
select type(arg)
type is (real(kind=kind(1d0)))
pp => norm_r8
type is (real)
pp => norm_r
type is (integer)
pp => norm_i
type is (complex)
pp => norm_c
class default
pp => null()
end select
end subroutine
end module
program test
use proc
implicit none
real(kind=kind(1d0)) :: arg_r8
real :: arg_r
integer :: arg_i
complex :: arg_c
procedure(), pointer :: pNorm => null()
arg_r8 = 4.0123456789d30
arg_r = 12.5
arg_i = 56
arg_c = (34,3)
call get_proc_ptr(pNorm, arg_r8)
call pNorm(arg_r8)
call get_proc_ptr(pNorm, arg_r)
call pNorm(arg_r)
call get_proc_ptr(pNorm, arg_i)
call pNorm(arg_i)
call get_proc_ptr(pNorm, arg_c)
call pNorm(arg_c)
end program
And here is the output of this program:
$ ./testprocptr
real8: 4.0123456788999999E+030
real: 12.5000000
integer: 56
complex: ( 34.0000000 , 3.00000000 )
If I understand well, you want to achieve two things at one time.
First, you want to use polymorphism to let the compiler call the correct routine dependent on whether you have a different type, rank, number of arguments etcetera.
Second, you want to use procedure pointers to switch between different procedures that have the same interface.
I tried the same. I did not manage to set a pointer to an interface, but I managed to make an interface with pointers.
If you have a module like this
module some_module
! This is the abstract interface for procedure pointers.
interface
subroutine shape_1_interface(arg)
implicit none
real, intent(in) :: arg
end subroutine shape_1_interface
subroutine shape_2_interface(arg)
implicit none
integer, intent(in) :: arg
end subroutine shape_2_interface
end interface
contains
subroutine routine_shape_1_implementation_1(arg)
implicit none
real, intent(in) :: arg
write(*,*) "Arg is real",arg
write(*,*) "Implementation 1"
end subroutine routine_shape_1_implementation_1
subroutine routine_shape_2_implementation_1(arg)
implicit none
integer, intent(in) :: arg
write(*,*) "Arg is int",arg
write(*,*) "Implementation 1"
end subroutine routine_shape_2_implementation_1
subroutine routine_shape_1_implementation_2(arg)
implicit none
real, intent(in) :: arg
write(*,*) "Arg is real",arg
write(*,*) "Implementation 2"
end subroutine routine_shape_1_implementation_2
subroutine routine_shape_2_implementation_2(arg)
implicit none
integer, intent(in) :: arg
write(*,*) "Arg is int",arg
write(*,*) "Implementation 2"
end subroutine routine_shape_2_implementation_2
subroutine routine_shape_1_implementation_3(arg)
implicit none
real, intent(in) :: arg
write(*,*) "Arg is real",arg
write(*,*) "Implementation 3"
end subroutine routine_shape_1_implementation_3
subroutine routine_shape_2_implementation_3(arg)
implicit none
integer, intent(in) :: arg
write(*,*) "Arg is int",arg
write(*,*) "Implementation 3"
end subroutine routine_shape_2_implementation_3
end module some_module
then you can do in your main program:
program main
use some_module
implicit none
procedure(shape_1_interface), pointer :: routine_shape_1
procedure(shape_2_interface), pointer :: routine_shape_2
interface routine
procedure routine_shape_1
procedure routine_shape_2
end interface routine
routine_shape_1 => routine_shape_1_implementation_1
routine_shape_2 => routine_shape_2_implementation_1
call routine(4)
routine_shape_1 => routine_shape_1_implementation_2
routine_shape_2 => routine_shape_2_implementation_2
call routine(4.0)
end program main
It is a pity that when you want to set the pointers to a different implementation, you have to do that for all shapes, but the good thing is that you can just call 'routine' and you automatically get the desired function.
This is the output:
Arg is int 4
Implementation 1
Arg is real 4.00000000000000
Implementation 2

Cannot assign initial value to derived data type in a module

In a Fortran module, I'm trying to assign initial value to a derived data type whose component is a procedure pointer, but get an error message: unexpected pointer assignment.
In a module, how to assign initial value to a derived type containing a procedure pointer?
module pointer_mod
use legendrePolynomials
implicit none
interface
function func (z)
real*8 :: func
real*8, intent (in) :: z
end function func
end interface
type proc_ptr
procedure (func), pointer, nopass :: f_ptr
end type proc_ptr
type(proc_ptr), dimension(6) :: basis
basis(1) % f_ptr => Legendre0 ! or basis(1) % f_ptr => null()
end module pointer_mod
where:
function Legendre0(x) result(y)
real, intent(in) :: x
real :: y
y = 1
end function
You get the error message, because you issue an pointer assignment outside of any subroutines, where usually only declarations should occur. Putting the assignment in a subroutine (see below) shows, that things work perfectly, provided you make sure, the Legendre0() function also use real*8 type in order to match the interface declaration (for testing purposes, I also put the Legendre function in the same module):
module pointer_mod
implicit none
interface
function func (z)
real*8 :: func
real*8, intent (in) :: z
end function func
end interface
type proc_ptr
procedure (func), pointer, nopass :: f_ptr
end type proc_ptr
type(proc_ptr), dimension(6) :: basis
contains
subroutine test()
basis(1)%f_ptr => Legendre0 ! or basis(1) % f_ptr => null()
end subroutine test
function Legendre0(x) result(y)
real*8, intent(in) :: x
real*8 :: y
y = 1
end function Legendre0
end module pointer_mod
As an additional comment: You should consider to declare your real variables like
integer, parameter :: dp = kind(1.0d0)
real(dp) :: whatever
instead of the real*8 notation, which is obsolate.
Another solution would be to make the function pointer of Legendre0 the default for all variables of type(proc_ptr).
type proc_ptr
procedure (func), pointer, nopass :: f_ptr => Legendre0
end type proc_ptr
But that's probably not what you want because you're handling an array of pointers.

Resources