Can the shape of an array in an interface match multiple fixed array size?
Asked Answered
G

1

1

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

  1. it's like I'm loosing some information just for making the compiler happy without adding any kind of security

  2. 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).

Gradygrae answered 3/6, 2015 at 12:49 Comment(2)
Note: (*) is assumed size, not assumed shape. The difference is actually important. Assumed shape is (:).Radiancy
@VladimirF thanks, corrected, I was abused by compiler error messageGradygrae
P
3

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.

  1. If the interface of a dummy procedure is explicit, its characteristics as a procedure (12.3.1) shall be the same as those of its effective argument, except that [inapplicable things]

f in indirect is a dummy procedure with an explicit interface (through the interface block; 12.4.2.1). Looking at the reference 12.3.1 we see

The characteristics of a procedure are .. , the characteristics of its dummy arguments, ..

foo, bar and f are all procedures with a single dummy argument (all called p, by coincidence). So, if foo wants to be the effective argument associated with f then foo's p must match the characteristics of f's p. Each p is a dummy data object, so 12.3.2.2 becomes relevant:

The characteristics of a dummy data object are its type, its type parameters (if any), its shape, ... If a shape, size, or type parameter is assumed or deferred, it is a characteristic.

We have that the type and type parameters match. However, p in f has its size assumed. p in foo does not have this matching characteristic. It is, then, not allowed to associate foo with f in the call to indirect. The same holds for bar.

This requirement for matching characteristics of the dummy data objects to have the same shape also leads naturally to another conclusion: foo and bar 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 and bar 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, in indirect 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...

Pilchard answered 3/6, 2015 at 16:32 Comment(3)
thanks, that must match gfortran interpretation indeed. But if I degrade the signature of foo and bar as assumed dimension() they then match the interface and the compiler stay quiet... It's purely artificial because one will still use 2 and the other 3 elements in p... And I guess the implementation just uses a raw pointer to first array element in both case, be the dimension assumed () or explicit (2), so they are binary compatible... I feel like speaking of explicit interface with assumed array size is somehow wooly ;)Gradygrae
Assumed shape/size are indeed quite different from explicit. If you feel the explicit shape is important (and it could be) then I can think of two things: it doesn't make sense to want to lump them together through indirect; have indirect's f have an implicit interface (scrap the interface block). This last one I should probably actually put in the answer...Pilchard
yes, indirect makes no sense in my example, but it could be an ODE solver, a SLLSQP solver or whatever... And if I use the solver for different problems, I will have varying size.Gradygrae

© 2022 - 2024 — McMap. All rights reserved.