- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi everyone, I'm writing a library for some scientific computations, which I am trying to make it as general as possible, so that each future user can use it at its own wishes.
For that, in my derived types I hence thought to use some function pointers, which might point to functions provided by the user.
Here is an example:
module mytype
implicit none
private
type, public :: mytype_t
integer :: val = 0
procedure(), pointer, nopass :: evalFct => null()
contains
procedure, public, pass :: setFctPtr
end type
contains
subroutine setFctPtr(this, fptr)
class(mytype_t) :: this
procedure(), intent(in), pointer :: fptr
this%evalFct => fptr
end subroutine setFctPtr
end module
program main
use mytype
implicit none
type(mytype_t) :: t
character(len=132) :: filename
call t%setFctPtr(eval)
! call member function pointer.
! NOTE: has nopass, so pass reference to itself.
call t%evalFct(t, filename)
contains
subroutine eval(t, arg)
class(mytype_t) :: t
character(len=*), intent(in) :: arg
! after some logic, try to modify "t"
! NOTE: here I get access violation exception
! after calling the function pointer
t%val = 5
end subroutine eval
end program
If you read along the lines, after calling the derived type instance's function pointer, I get an access violation exception as soon as I try to access the instance itself (from within the pointed function).
Is it maybe a problem to access the instance from within itself ? I don't even know if what I am saying makes sense or not.
Also, if you got the idea of what I'd like to achieve, and have better suggestions on how to do it, I'm more than open to hear and learn from them.
Michele
EDIT:
after posting the answer which might contain the solution, it is still unclear why that modification solved the problem.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You've several options but before I get into that, I will strongly suggest you consider explicit interfaces especially if you're considering future users and keeping your design general (and also "safe" I presume). So the options I below below include explicit interfaces and one of them is along the lines of what you have discovered though what the explicit interfaces do is make things clearer for both the compiler and the readers of the program and which also enables functioning without run-time errors.
* Option 1: likely the easier option and the more general one for your future users
module mytype
implicit none
private
type, public :: mytype_t
integer :: val = 0
procedure(Ieval), pointer :: evalFct => null()
contains
procedure, public, pass :: setFctPtr
end type
abstract interface
subroutine Ieval(t, arg)
import :: mytype_t
class(mytype_t), intent(inout) :: t
character(len=*), intent(in) :: arg
end subroutine
end interface
contains
subroutine setFctPtr(this, fptr)
class(mytype_t) :: this
procedure(Ieval), intent(in), pointer :: fptr
this%evalFct => fptr
end subroutine setFctPtr
end module
program main
use mytype
implicit none
type(mytype_t) :: t
character(len=132) :: filename
call t%setFctPtr(eval)
call t%evalFct( filename ) !<-- note only parameter within parentheses
print *, "t%val = ", t%val, "; expected is 5"
contains
subroutine eval(t, arg)
class(mytype_t), intent(inout) :: t
character(len=*), intent(in) :: arg
t%val = 5
end subroutine eval
end program
* Option 2: this is along your original post but why bother when you have option 1 above!
module mytype
implicit none
private
type, public :: mytype_t
integer :: val = 0
procedure(Ieval), nopass, pointer :: evalFct => null()
contains
procedure, public, pass :: setFctPtr
end type
abstract interface
subroutine Ieval(t, arg)
import :: mytype_t
class(mytype_t), intent(inout) :: t
character(len=*), intent(in) :: arg
end subroutine
end interface
contains
subroutine setFctPtr(this, fptr)
class(mytype_t) :: this
procedure(Ieval), intent(in), pointer :: fptr
this%evalFct => fptr
end subroutine setFctPtr
end module
program main
use mytype
implicit none
type(mytype_t) :: t
character(len=132) :: filename
call t%setFctPtr(eval)
call t%evalFct(t, filename ) !<-- note two parameters within parentheses
print *, "t%val = ", t%val, "; expected is 5"
contains
subroutine eval(t, arg)
class(mytype_t), intent(inout) :: t
character(len=*), intent(in) :: arg
t%val = 5
end subroutine eval
end program
* Option 3: eschew polymorphism with the passed type but it may curtail the generality you seek, meaning Option 1 still is likely a better choice for you.
module mytype
implicit none
private
type, public :: mytype_t
integer :: val = 0
procedure(Ieval), nopass, pointer :: evalFct => null()
contains
procedure, public, pass :: setFctPtr
end type
abstract interface
subroutine Ieval(t, arg)
import :: mytype_t
type(mytype_t), intent(inout) :: t
character(len=*), intent(in) :: arg
end subroutine
end interface
contains
subroutine setFctPtr(this, fptr)
class(mytype_t) :: this
procedure(Ieval), intent(in), pointer :: fptr
this%evalFct => fptr
end subroutine setFctPtr
end module
program main
use mytype
implicit none
type(mytype_t) :: t
character(len=132) :: filename
call t%setFctPtr(eval)
call t%evalFct(t, filename ) !<-- note two parameters within parentheses
print *, "t%val = ", t%val, "; expected is 5"
contains
subroutine eval(t, arg)
type(mytype_t), intent(inout) :: t
character(len=*), intent(in) :: arg
t%val = 5
end subroutine eval
end program
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Actually, I probably come to find the solution myself.
Apparently, by changing from `class(mytype_t)` to `type(mytype_t)` in `eval()` function in the main program solved the problem.
However, the reason why this change clears the *access violation* exception is still unclear to me.
Hope to hear from someone.
Best wishes,
Michele
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
A CLASS declares a polymorphic object whereas TYPE does not. A polymorphic object can have differing types during program execution.
In order to access member variables of a polymorphic object, the compiler must know which of potentially several CLASS and/or TYPES is being referenced. See SELECT TYPE
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
You've several options but before I get into that, I will strongly suggest you consider explicit interfaces especially if you're considering future users and keeping your design general (and also "safe" I presume). So the options I below below include explicit interfaces and one of them is along the lines of what you have discovered though what the explicit interfaces do is make things clearer for both the compiler and the readers of the program and which also enables functioning without run-time errors.
* Option 1: likely the easier option and the more general one for your future users
module mytype
implicit none
private
type, public :: mytype_t
integer :: val = 0
procedure(Ieval), pointer :: evalFct => null()
contains
procedure, public, pass :: setFctPtr
end type
abstract interface
subroutine Ieval(t, arg)
import :: mytype_t
class(mytype_t), intent(inout) :: t
character(len=*), intent(in) :: arg
end subroutine
end interface
contains
subroutine setFctPtr(this, fptr)
class(mytype_t) :: this
procedure(Ieval), intent(in), pointer :: fptr
this%evalFct => fptr
end subroutine setFctPtr
end module
program main
use mytype
implicit none
type(mytype_t) :: t
character(len=132) :: filename
call t%setFctPtr(eval)
call t%evalFct( filename ) !<-- note only parameter within parentheses
print *, "t%val = ", t%val, "; expected is 5"
contains
subroutine eval(t, arg)
class(mytype_t), intent(inout) :: t
character(len=*), intent(in) :: arg
t%val = 5
end subroutine eval
end program
* Option 2: this is along your original post but why bother when you have option 1 above!
module mytype
implicit none
private
type, public :: mytype_t
integer :: val = 0
procedure(Ieval), nopass, pointer :: evalFct => null()
contains
procedure, public, pass :: setFctPtr
end type
abstract interface
subroutine Ieval(t, arg)
import :: mytype_t
class(mytype_t), intent(inout) :: t
character(len=*), intent(in) :: arg
end subroutine
end interface
contains
subroutine setFctPtr(this, fptr)
class(mytype_t) :: this
procedure(Ieval), intent(in), pointer :: fptr
this%evalFct => fptr
end subroutine setFctPtr
end module
program main
use mytype
implicit none
type(mytype_t) :: t
character(len=132) :: filename
call t%setFctPtr(eval)
call t%evalFct(t, filename ) !<-- note two parameters within parentheses
print *, "t%val = ", t%val, "; expected is 5"
contains
subroutine eval(t, arg)
class(mytype_t), intent(inout) :: t
character(len=*), intent(in) :: arg
t%val = 5
end subroutine eval
end program
* Option 3: eschew polymorphism with the passed type but it may curtail the generality you seek, meaning Option 1 still is likely a better choice for you.
module mytype
implicit none
private
type, public :: mytype_t
integer :: val = 0
procedure(Ieval), nopass, pointer :: evalFct => null()
contains
procedure, public, pass :: setFctPtr
end type
abstract interface
subroutine Ieval(t, arg)
import :: mytype_t
type(mytype_t), intent(inout) :: t
character(len=*), intent(in) :: arg
end subroutine
end interface
contains
subroutine setFctPtr(this, fptr)
class(mytype_t) :: this
procedure(Ieval), intent(in), pointer :: fptr
this%evalFct => fptr
end subroutine setFctPtr
end module
program main
use mytype
implicit none
type(mytype_t) :: t
character(len=132) :: filename
call t%setFctPtr(eval)
call t%evalFct(t, filename ) !<-- note two parameters within parentheses
print *, "t%val = ", t%val, "; expected is 5"
contains
subroutine eval(t, arg)
type(mytype_t), intent(inout) :: t
character(len=*), intent(in) :: arg
t%val = 5
end subroutine eval
end program
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
many thanks for your answer. Very, very clear.
I do agree, the third option is out of consideration, and the first is the one to be preferred.
And yeah, I do agree about the fact that having explicit interfaces prevents compile but specially runtime errors.
Indeed, I had choosen the approach of implicit interface function pointer member variable, since a-priori I don't know which is the function that the user will pass.
However, I think that what I reasoned in a first place does not actually have much sense, since I would not be able to then call the function pointer myself internally since I would not know how to do it (should always be the user to call it, so at that point, it falls the need of having an internal function pointer).
However, I learned from your answers @FortranFan @jimdempseyatthecove , and I am grateful for that.
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page