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

Generic interface for two subroutines with allocatable and pointer arguments

pacobraxe
Beginner
1,134 Views
Hi all,

I want to create two subroutines, one working with pointer arguments and the other with allocatable arguments. I'd like to use the same name (through a generic interface). The problem is that ifort (Version 11.1) gives an error:

pru_allo_poin.f90(15): warning #6738: The type/rank/keyword signature for this specific procedure matches another specific procedure that shares the same generic-name. [SUB_P]

Should it be the the usual behaviour? Thanks.

This is the Fortran code:

module modu
private :: sub_a, sub_p
interface sub; module procedure sub_a; end interface
interface sub; module procedure sub_p; end interface
contains
subroutine sub_a
integer, dimension(:), allocatable :: a
print*, a
end subroutine
subroutine sub_p
integer, dimension(:), pointer :: p
print*, p
end subroutine
end module

program ppal
use modu
implicit none
integer, dimension(:), allocatable :: a
integer, dimension(:), pointer :: p
allocate(a(10))
allocate(p(10))
call sub(a)
call sub(p)
end program
0 Kudos
1 Solution
Ron_Green
Moderator
1,134 Views
this is what you want to do:

module modu
contains
subroutine sub(p)
integer, dimension(:) :: p
print*, p
end subroutine

end module

program ppal
use modu
implicit none
integer, dimension(:), allocatable :: a
integer, dimension(:), pointer :: p
allocate(a(10))
allocate(p(10))
call sub(a)
call sub(p)
end program

View solution in original post

0 Kudos
14 Replies
jimdempseyatthecove
Honored Contributor III
1,134 Views

You are declaring sub twice, each time without arguments. Then later calling sub twice, each with one different argument. Did you mean something like

interface sub
subroutine sub_a(a) ! *** note dummy argument a
implicit none
integer, dimension(:), allocatable :: a
end subroutine sub_a
subroutine sub_p(p) ! *** note dummy argumentp
implicit none
integer, dimension(:), pointer :: p
end subroutine sub_p
end interface

Jim Dempsey
0 Kudos
Ron_Green
Moderator
1,134 Views
I think the bigger issue is that the set of procedures associated with a given generic name must form an unambiguous set. Essentially, the arguments must differ from each other in type or rank. Both a and p are of the same type and rank.

I am sure there is a blurb in the standard on this.

Even if you do this:

module modu
private :: sub_a, sub_p
interface sub
module procedure sub_a, sub_p
end interface
public sub

contains
subroutine sub_a(a)
integer, dimension(:), allocatable :: a
print*, a
end subroutine

subroutine sub_p(p)
integer, dimension(:), pointer :: p
print*, p
end subroutine
end module

program ppal
use modu
implicit none
integer, dimension(:), allocatable :: a
integer, dimension(:), pointer :: p
allocate(a(10))
allocate(p(10))
call sub(a)
call sub(p)
end program


which looks correct, gives the following:

$ gfortran generic2.f90
generic2.f90:4.31:

module procedure sub_a, sub_p
1
Error: Ambiguous interfaces 'sub_p' and 'sub_a' in generic interface 'sub' at (1)
generic2.f90:21.8:


and

$ ifort generic2.f90
generic2.f90(14): warning #6738: The type/rank/keyword signature for this specific procedure matches another specific procedure that shares the same generic-name. [SUB_P]
subroutine sub_p(p)
-----------^

Ifort is giving a better clue "type/rank/keyword" signature don't differ. Obviously type/rank are not different. But keyword, hmmm....

I'll dig up the standard and see what it says. it could be that allocatable and pointer keywords don't differentiate.

ron
0 Kudos
Ron_Green
Moderator
1,134 Views
Got it, in the Fortran 2003 standard, Note 12.9

... the POINTER attribute cannot be used to resolve generic procedures (16.2.3), so it is not possible to define a generic operator that has one procedure for pointers and another procedure for nonpointers.
0 Kudos
Ron_Green
Moderator
1,135 Views
this is what you want to do:

module modu
contains
subroutine sub(p)
integer, dimension(:) :: p
print*, p
end subroutine

end module

program ppal
use modu
implicit none
integer, dimension(:), allocatable :: a
integer, dimension(:), pointer :: p
allocate(a(10))
allocate(p(10))
call sub(a)
call sub(p)
end program

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,134 Views

From my understanding of the original post the user wanted to disambiguate between a pointer and an allocatable and then call a seperate routine. One way to do this is not by way of compiler but by way of code the looks at the descriptor. A second way to do this by way of the compiler is to create two user types, one containing an allocatable and the other containing a pointer.

Jim
0 Kudos
Steven_L_Intel1
Employee
1,134 Views
For generic resolution, only the Type, Kind and Rank of arguments are considered. Each specific procedure in a generic must be distinguishable from all others by type, kind and/or rank. Other attributes, such as ALLOCATABLE or POINTER are not considered. I believe that the error message has a typo and that "keyword" should be "kind". It is also possible that "keyword" refers to the use of dummy argument names as keywords in a call, as in cases with OPTIONAL arguments these can be used to distinguish on definition, but it seems wrong here...

Ron's suggestion works if the called routine is not going to change the allocation status of the argument or redefine the pointer. Jim has a good suggestion in a general way, using derived types, but that's probably not going to be acceptable here. Looking at the descriptor is of no help.

Perhaps if pacobraxe explained in more detail what is needed here, we could offer other suggestions.
0 Kudos
pacobraxe
Beginner
1,134 Views
For generic resolution, only the Type, Kind and Rank of arguments are considered. Each specific procedure in a generic must be distinguishable from all others by type, kind and/or rank. Other attributes, such as ALLOCATABLE or POINTER are not considered. I believe that the error message has a typo and that "keyword" should be "kind". It is also possible that "keyword" refers to the use of dummy argument names as keywords in a call, as in cases with OPTIONAL arguments these can be used to distinguish on definition, but it seems wrong here...

Ron's suggestion works if the called routine is not going to change the allocation status of the argument or redefine the pointer. Jim has a good suggestion in a general way, using derived types, but that's probably not going to be acceptable here. Looking at the descriptor is of no help.

Perhaps if pacobraxe explained in more detail what is needed here, we could offer other suggestions.

Thanks to all for your valuable help. The original problem was the following:

I found a subroutine 'sub' in Internet to write scalar fields in VTK format. This subroutine receives pointer arguments because it follows the standard of Fortran 95 (arguments cannot be allocatable). I cannot easily change the code of the subroutine since it belongs to a bigger library and there are many cross calls between the procedures of the library.

Since I am trying to develop my own code close to Fortran 2003, I'd like to give the possibility to use allocatable arrays with 'sub'. My solution consisted of creating another subroutine 'sub2' with allocatable arguments, create local pointers associated to that arguments and call the original 'sub' with pointer arguments. In order to avoid using two names, I wrote an interface.

I think the solution given by Ronald is very elegant, but I do know how to apply it since I cannot change the original 'sub'. The same can be said about creating user types (jimdempseyatthecove).

Thanks again,
Paco
0 Kudos
jimdempseyatthecove
Honored Contributor III
1,134 Views

Paco,

Wherever you have (in your code)

real, allocatable :: array(:)

Change to

real, allocatable :: allocatable_array(:)
real, pointer :: array(:)

And where you allocate

allocate(array(yourSize))

change to

allocate(allocatable_array(yourSize))
array => allocatable_array

Now all code (yours and lib) can use

sub(array)

Jim Dempsey


0 Kudos
may_ka
Beginner
1,134 Views

Hi,

want to come back on this issue.

I have exactly that problem.

Moreover, in the subroutine the dummy array has to be "allocatable" because bounds can change (start with zero). When I implement a single subroutine like

subroutine aAllo(in)

Implicit None

integer, intent(inout, allocatable, dimension(:) :: in

end subroutine aAllo

a call with call a(b), where b is "allocatable" works, but a call where b is a pointer does not compile.

Thus, I implemented another subroutine

subroutine aPointer(in)

Implicit None

integer, intent(inout), pointer, dimension(:) :: in

end subroutine aPointer

and for both

Interface doSomething

 Module Procedure :: aAllo

 Module Procedure :: aPointer

End Interface

However, this does not compile with error message : "The type/rank/keyword signature for this specific procedure matches another specific procedure that shares the same generic-name"

Is there anything wrong with the way I implemented that??? Otherwise the compiler behaviour is inconsistend.

Any idea

thanks

Karl

0 Kudos
FortranFan
Honored Contributor II
1,133 Views

may.ka wrote:

Hi,

want to come back on this issue.

I have exactly that problem.

Moreover, in the subroutine the dummy array has to be "allocatable" because bounds can change (start with zero). When I implement a single subroutine like

[fortran]

subroutine aAllo(in)

Implicit None

integer, intent(inout, allocatable, dimension(:) :: in

end subroutine aAllo

[/fortran]

a call with call a(b), where b is "allocatable" works, but a call where b is a pointer does not compile.

Karl,

Why do you need ALLOCATABLE attribute on the dummy argument in?  Why can't leave it as assumed shape instead i.e., as DIMENISION(:)?  I'd think that will do what you're looking for.

If you remove the ALLOCATABLE attribute, both your calls - where b is an allocatable and where b is a defined pointer with valid data/association, should work.

0 Kudos
Steven_L_Intel1
Employee
1,133 Views

Answering Karl's initial question, being able to distinguish generics by the POINTER/ALLOCATABLE attribute alone is new in Fortran 2008. It seems that we partially implement this - at least an example I concocted using Karl's fragment compiles with only a warning, not an error, and the generic is properly resolved based on whether the actual argument is a pointer or allocatable. We don't claim that we support this F2008 feature yet and I've asked the developers for the status, based on the results I see.

0 Kudos
may_ka
Beginner
1,133 Views

Hi all,

thanks.

@FortranFan

the "allocatable" is necessary for a function which extends a matrix by one column (e.g. cbind in "R"). The subroutine looks like this:

Subroutine cBind(matrix,vector)
Implicit None
Real, Allocatable, Dimension(:,:), Intent(inout) :: matrix
Real, Intent(in), Dimension(:) :: vector
Real, Dimension(:,:), allocatable :: tmp
if(allocated(matrix)) then
allocate(tmp(size(matrix,1),size(matrix,2)+1)
tmp(:,1:size(matrix,2))=matrix
tmp(:,size(tmp,2))=vector
move_alloc(tmp,matrix)
else
allocate(matrix(size(vector,1),1)
matrix(:,1)=vector
end if
end subroutine cBind

Of course in "real life" it is a bit more complex to cache all possible errors when calling or to get the index bounds right. However, as you see, without the allocatable attribute neither "move_alloc" nor "allocate" woud not be possible.

0 Kudos
FortranFan
Honored Contributor II
1,133 Views

may.ka wrote:

...

@FortranFan

the "allocatable" is necessary for a function which extends a matrix by one column (e.g. cbind in "R"). ..

Of course in "real life" it is a bit more complex to cache all possible errors when calling or to get the index bounds right. However, as you see, without the allocatable attribute neither "move_alloc" nor "allocate" woud not be possible.

I see.  In that case, you do need the new Fortran 2008 feature of "generic resolution by ALLOCATABLE/POINTER attribute".  See Steve's notes above - it appears Intel Fortran may provide a partial implementation, you may need to investigate how well it works for your needs, and some tesing may be called for.  I am sure Intel and the forum readers would appreciate your feedback on the findings.

0 Kudos
Steven_L_Intel1
Employee
1,133 Views

The 15.0 compiler can now distinguish a generic by ALLOCATABLE vs. POINTER.

0 Kudos
Reply