- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
In the core below, I get an error stating that the characteristics of the first argument of the actual procedure do not match those of the dummy procedure.
module mod1 type, abstract :: t1 integer :: dummy1 = 0 contains procedure :: execute end type abstract interface subroutine i_t1(this) import class(t1), intent(INOUT) :: this end subroutine end interface contains subroutine execute(this, proc) class(t1), intent(INOUT) :: this procedure(i_t1) :: proc call proc(this) end subroutine end module mod1 module mod2 use mod1 type, abstract, extends(t1) :: t2 integer :: dummy2 = 0 contains procedure :: handler2 end type contains subroutine handler2(this) class(t2), intent(INOUT) :: this end subroutine end module mod2 module mod3 use mod2 type, extends(t2) :: t3 integer :: dummy3 = 0 contains procedure :: handler3 procedure :: do_something end type contains subroutine handler3(this) class(t3), intent(INOUT) :: this end subroutine subroutine do_something(this) class(t3), intent(INOUT) :: this call this%execute(handler2) call this%execute(handler3) end subroutine end module mod3
Even if t2 is not an abstract type, there seems to be no way of passing handler2 or handler3 to the type-bound procedure (I already tried the f95 way as well).
Is it a bug in the implementation? Or is the compiler right at complaining here?
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hello John
How about changing the handlers 2 as :
subroutine handler2(this)
class(t1), intent(INOUT) :: this
end subroutine
subroutine handler3(this)
class(t1), intent(INOUT) :: this
end subroutine
and using nopass:
procedure, nopass :: handler2
procedure, nopass :: handler3
This should compile I think
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I'm not really looking for workarounds to make it just compile, and that particular workaround doesn't work for me ---since, in the actual code, handler2 and handler3 would have to invoke type-bound procedures from t2 and t3, respectively.
It just seems like weird behavior to me, and I would like to be certain that I'm not doing something wrong.
The following code fails to compile as well, so the issue is not related to the ABSTRACT attribute of t1:
module mod1 type :: t1 integer :: dummy1 = 0 contains procedure :: execute end type abstract interface subroutine i_t1(this) import class(t1), intent(INOUT) :: this end subroutine end interface contains subroutine execute(this, proc) class(t1), intent(INOUT) :: this procedure(i_t1) :: proc call proc(this) end subroutine end module mod1 module mod2 use mod1 type, extends(t1) :: t2 integer :: dummy2 = 0 contains procedure :: do_something end type contains subroutine handler2(this) class(t2), intent(INOUT) :: this end subroutine subroutine do_something(this) class(t2), intent(INOUT) :: this procedure(i_t1), pointer :: pp pp => handler2 call this%execute(pp) end subroutine end module mod2
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
John wrote:
...
Is it a bug in the implementation? Or is the compiler right at complaining here?
I think the compiler is right; you can comb through the Fortran standards documentation and see if you find something that supports your case, but I'll be surprised if you find any other compiler that accepts this.
Separately, from a polymorphism and OO design point of view, your code doesn't make much sense to me and I can't identify the design pattern and a practical value of such an approach. Why do you need a construct such as [fortran]call this%execute(handler2)[/fortran] when you can do [fortran]call this%handler2()[/fortran] directly and accrue all the benefits of class design, inheritance, and polymorphism in this simpler way?
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
This is not a bug. Unlike with direct calls, procedure pointers must have the SAME interface, not just compatible interfaces.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
FortranFan wrote:
I think the compiler is right; you can comb through the Fortran standards documentation and see if you find something that supports your case, but I'll be surprised if you find any other compiler that accepts this.
Separately, from a polymorphism and OO design point of view, your code doesn't make much sense to me and I can't identify the design pattern and a practical value of such an approach. Why do you need a construct such as
call this%execute(handler2)when you can do
call this%handler2()directly and accrue all the benefits of class design, inheritance, and polymorphism in this simpler way?
Most of the code in this forum doesn't have to make sense. It only has to prove a point (in this case, the point is showing the error thrown by the compiler). It's actually the second time you fail to realize that.
In the actual code the base abstract class implements a comparison of methods for doing certain things, and each handler implements a particular method. The this%execute() procedure would actually be this%addSomeMethodOfComputingThings(), and just stores a pointer to the procedure passed as argument, to be called later; and it stores many of those. Another procedure in the base class calls them one after another, compares and outputs the results ---and for some reason that makes sense to me.
The actual code compiled and ran just fine with a previous version of ifort (even with some of the methods being in separate libraries, loaded through dlfcn and C_F_PROCPOINTER), but with the latest version it throws an error.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve Lionel (Intel) wrote:
This is not a bug. Unlike with direct calls, procedure pointers must have the SAME interface, not just compatible interfaces.
Steve, in the original code I posted, there are no procedure pointers. It's just procedures being passed as arguments. The argument of each of those procedures being passed, satisfies the required interface (since it's of the same class), but the compiler sees differently.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Right - we fixed a bug. The standard says:
"If proc-pointer-object has an explicit interface, its characteristics shall be the same as proc-target except that proc-target may be pure even if proc-pointer-object is not pure and proc-target may be an elemental intrinsic procedure even if proc-pointer-object is not elemental." [F2008, p160, lines 6-8]
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Steve,
The text you cite mentions "explicit interface", and that made me think of a somewhat riskier approach: Is the following code valid? Or does it just work because of a yet-to-be-fixed bug?
module mod1 type :: availableMethods procedure(i_compute), pointer, nopass :: proc => NULL() end type type :: compute type(availableMethods) :: methods(2) contains procedure :: addMethod procedure :: execute end type abstract interface subroutine i_compute(this) import class(compute), intent(INOUT) :: this end subroutine end interface contains subroutine addMethod(this, proc) class(compute), intent(INOUT) :: this procedure() :: proc integer :: i, idx idx = 0 do i = 1, SIZE(this%methods) if (.NOT. ASSOCIATED(this%methods(i)%proc)) then idx = i exit endif enddo if (idx == 0) then write (*,'(A)') 'Cannot add more' return endif this%methods(idx)%proc => proc end subroutine subroutine execute(this) class(compute), intent(INOUT) :: this integer :: i do i = 1, SIZE(this%methods) if (.NOT. ASSOCIATED(this%methods(i)%proc)) cycle call this%methods(i)%proc(this) enddo end subroutine end module mod1 module mod2 use mod1 type, extends(compute) :: implement integer :: dummy = 0 contains procedure :: do_something end type contains subroutine handler(this) class(implement), intent(INOUT) :: this call this%do_something() end subroutine subroutine do_something(this) class(implement), intent(INOUT) :: this write (*, '(A)') 'Doing something' end subroutine end module mod2 use mod2 type(implement) :: a call a%addMethod(handler) call a%execute() end
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I quoted the wrong part of the standard. You're passing a procedure dummy argument. But the same issue arises - the characteristics of the arguments must be the same and yours are not.

- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page