Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28492 Discussions

Derived-type implicit interface procedure pointer, access violation error.

mic_esp96
New Contributor I
566 Views

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.

0 Kudos
1 Solution
FortranFan
Honored Contributor II
503 Views

@mic_esp96 ,

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

 

View solution in original post

4 Replies
mic_esp96
New Contributor I
541 Views

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

0 Kudos
jimdempseyatthecove
Honored Contributor III
530 Views

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

 

FortranFan
Honored Contributor II
504 Views

@mic_esp96 ,

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

 

mic_esp96
New Contributor I
443 Views

@FortranFan ,

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.

 

 

Reply