Derived-type procedure pointer not able to point to subroutine with extended type as argument

Derived-type procedure pointer not able to point to subroutine with extended type as argument

Hi,

The following code compiles and works under the GNU fortran compiler. On the Intel compiler I get: 

error #8178: The procedure pointer and the procedure target must have matching arguments.
mytype%point1 => type2subroutine

Here is the code:

module mod_type1
implicit none

type :: type1
procedure(type1interface), pointer :: point1
end type

interface
subroutine type1interface(a)
import type1
implicit none
class(type1) :: a

end subroutine
end interface

type, extends(type1) :: type2
end type

contains
subroutine type2subroutine(a)
implicit none
class(type2) :: a

write(*,*) 'hello pointer'

end subroutine
end module

program Main
use mod_type1
implicit none

type(type2) :: mytype

mytype%point1 => type2subroutine
call mytype%point1

end program

Should this work under the F2003 standard?

Thanks,

Joan

8 Beiträge / 0 neu
Letzter Beitrag
Nähere Informationen zur Compiler-Optimierung finden Sie in unserem Optimierungshinweis.

No, this is not legal in either F2003 or F2008. F2003 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." [F2003, p144, lines 39-41]

F2008 has identical wording on p160, lines 6-8.

Note that it says "characteristics shall be the same".  This is not like data pointer assignment where the requirement is only "type-compatible".

Steve - Intel Developer Support

Here is a work-around which works for both gnu and intel compilers, but i don't think it fulfills F2003 either, am I right?

module mod_type1
implicit none

private
public type1

type :: type1
procedure(type1interface), pointer :: point1

contains
procedure :: AssignProcedure

end type

interface
subroutine type1interface(a)
import type1
implicit none
class(type1) :: a

end subroutine
end interface

contains

subroutine AssignProcedure(a,proc1,proc2)
implicit none
class(type1) :: a
procedure(type1interface), pointer :: proc2
procedure(type1interface), pointer :: proc1

proc1 => proc2

end subroutine

end module mod_type1

module mod_type2

use mod_type1

type, extends(type1) :: type2
procedure(type2interface), pointer :: point2
end type

interface
subroutine type2interface(a)
import type2
implicit none
class(type2) :: a

end subroutine
end interface

contains

subroutine type2subroutine(a)
implicit none
class(type2) :: a

write(*,*) 'hello pointer'

end subroutine

end module

program Main
use mod_type1
use mod_type2
implicit none

type(type2) :: mytype

!mytype%point1 => type2subroutine
mytype%point2 => type2subroutine

call mytype%AssignProcedure(mytype%point1,mytype%point2)
call mytype%point1

end program

Thanks,

Joan

I would argue that this is also not allowed by the standard, for much the same reason as the first case. The rule for "Actual arguments associated with dummy procedure entries" (F2008 12.5.2.9) has very similar wording to what I quoted above. saying "its characteristics as a procedure (12.3.1) shall be the same as those of its effective dummy argument...". If one turns to 12.3.1 it includes the type of the procedure's dummy arguments, which are not the same here (class(type1) and class(type2)).

The program seems to work because type2subroutine doesn't use any components from the extended type, even though the pointer being called through is of the base type.

I will pass this on to the developers and see if they have a contrary opinion. Realistically, I don't see how this variant can be valid if the direct pointer assignment is not. Issue ID is DPD200242410.

Steve - Intel Developer Support

Even if this is not in the standard, I think that for an extended type, allowing procedure pointers inside the derived type with the pass atribute, which were defined in the parent type, to point to procedures which have the extended type as dummy argument, (the situation in the first case), is convenient and makes no harm (I cannot think of a situation where this would lead to segmentation fault etc).

I also think that allowing:

procedure(type1interface), pointer :: pointer1 
procedure(type2interface), pointer :: pointer2

pointer2 => pointer1

is convenient and makes no harm. So I would like to suggest this 2 features to be added to the compiler if you find it convenient.

Thanks,

Joan

We don't typically extend the compiler in this sort of direction. I think there are cases where it could cause problems. I recommend sticking with standard-conforming code for portability and maintainability.

Steve - Intel Developer Support

Quote:

jb84 wrote:

Even if this is not in the standard, I think that for an extended type, allowing procedure pointers inside the derived type with the pass atribute, which were defined in the parent type, to point to procedures which have the extended type as dummy argument, (the situation in the first case), is convenient and makes no harm (I cannot think of a situation where this would lead to segmentation fault etc).

I've seen this sort of thing in some example code recently on stack overflow, and this "proposal" was also recently put up on the Fortran wiki. I presume this isn't a coincidence.

Note that the above is not type safe - see the Fortran wiki for an explanation why.

I think this may have come up because of the rules around passed arguments, specifically C456 requiring that the passed object be the declared type of the type being defined and not a parent type.  Philosophically, the passed argument is associated with the thing that resulted in the procedure being invoked.  Note the thing - not the thing's parent, or grandparent etc.  As far as I can tell this is only a philosophical point and not a technical requirement (i.e. I think the constraint could be relaxed with the language as it is now, but you'd want to think long and hard about the current situation and possible future language directions before you changed things - particularly around specific procedure resolution, etc). 

Anyway, from that philosophical point - if you don't want the thing that resulted in the procedure being invoked being passed, then don't use a passed argument.  More philosophy - the "object%binding" and "object%proc-pointer-component" syntax is really all around either type based lookup or object based lookup of the procedure.  If you are not doing type based or object based lookup, then don't use that syntax.

I see the problem now, thank you for the clarification.

Kommentar hinterlassen

Bitte anmelden, um einen Kommentar hinzuzufügen. Sie sind noch nicht Mitglied? Jetzt teilnehmen