I have multiple subroutines with a parameter p which is an array of explicit size like
subroutine foo(p)
integer,dimension(2),intent(in) ::p
end subroutine foo
subroutine bar(p)
integer,dimension(3),intent(in) ::p
end subroutine bar
I'd like to call these two functions through an indirect call, but could not find a way to declare an interface that matches both foo and bar signature...
Using an assumed array size in the interface for example does not work:
subroutine indirect(f,p)
integer,dimension(*),intent(in):p
interface
subroutine f(p)
integer,dimension(*),intent(in) :: p
end subroutine f
end interface
call f(p)
end subroutine indirect
When I invoke foo or bar thru indirect, the compiler (gfortran 4.9.2) complains about shape mismatch for first argument p of f...
integer,dimension(2) :: pfoo
integer,dimension(3) :: pbar
pfoo = (/ 0,1 /)
pbar = (/ 1,2,3 /)
call foo(pfoo) ! direct call is OK
call bar(pbar)
call indirect(foo,pfoo) ! compiler complains about foo signature
call indirect(bar,pbar) ! same for bar...
Compiler error is something like:
Error: Interface mismatch in dummy procedure 'f' at (1): Shape mismatch in dimension 1 of argument 'p'
Of course, I could modify foo and bar signature to use assumed array size (*) instead of fixed array size, but
it's like I'm loosing some information just for making the compiler happy without adding any kind of security
foo and bar are not my code and I'd rather not change them...
I've found a workaround, but it consist of writing an assumed size wrapper for each subroutine foo and bar
call indirect(foo_wrapper,pfoo) ! compiler complains about foo signature
call indirect(bar_wrapper,pbar) ! same for bar...
subroutine foo_wrapper(p)
integer,dimension(*),intent(in) ::p
call foo(p)
end subroutine foo_wrapper
subroutine bar_wrapper(p)
integer,dimension(*),intent(in) ::p
call bar(p)
end subroutine bar_wrapper
or eventually, replacing all assumed size by deferred size in indirect and wrapper, so as to give a chance to runtime checks, also works, but that's not the point...
The point is, since I have many such foo/bar isn't there a way to declare the interface properly (I mean without wrappers or other artefacts).
I couldn't decipher the standard (I used http://www.j3-fortran.org/doc/year/10/10-007.pdf - I presume it's around 12.5.2.9 Actual arguments associated with dummy procedure entities §2), so I don't know if it's a limitation of gfortran. Right now i haven't any other compiler available, but I'd like to know if some other compiler would compile (intel? - I'm on windows 7 64 bits).
I'll look at whether gfortran is correct to complain and, regardless, what options there are to work around the complaint. References are to Fortran 2008.
12.5.2.9 is indeed important.
f
inindirect
is a dummy procedure with an explicit interface (through the interface block; 12.4.2.1). Looking at the reference 12.3.1 we seefoo
,bar
andf
are all procedures with a single dummy argument (all calledp
, by coincidence). So, iffoo
wants to be the effective argument associated withf
thenfoo
'sp
must match the characteristics off
'sp
. Eachp
is a dummy data object, so 12.3.2.2 becomes relevant:We have that the type and type parameters match. However,
p
inf
has its size assumed.p
infoo
does not have this matching characteristic. It is, then, not allowed to associatefoo
withf
in the call toindirect
. The same holds forbar
.This requirement for matching characteristics of the dummy data objects to have the same shape also leads naturally to another conclusion:
foo
andbar
don't have matching characteristics as procedures. For a third procedure to match both the shape characteristic must be ignored.Using a wrapper subroutine is possible, but I'd also think about whether I could change the various subroutines to take assumed-shape arguments. This is much better than assumed-size. But, as you say, I'd also be reluctant to change that code.
For the subroutines
foo
andbar
as you have them, there is another available option. Nothing about those subroutines requires a caller to have an explicit interface for them available (12.4.2.2). So, inindirect
you could just scrap the interface block: the rules about matching are much more relaxed (other parts of 12.5.2.9). For other procedures this may not be possible, though.All that said, ifort appears to happily compile and run the code as you have it...