- 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