I have a question about elemental procedures. I’m not sure if this should be categorized as Help or as Language Enhancement. It could be either, or both.
Look at this code:
program elem
implicit none
integer :: a = 0
integer :: b0, b1(-1:1), b2(2,2), b3(2,2,1)
call wanted ( a, b0 )
!call wanted ( a, b1 )
!call wanted ( a, b2 )
!call wanted ( a, b3 )
call sub( a, b0 )
print *, 'a=', a, 'b0=', b0
call sub( a, b1 )
print *, 'a=', a, 'b1=', b1
call sub( a, b2 )
print *, 'a=', a, 'b2=', b2
call sub( a, b3 )
print *, 'a=', a, 'b3=', b3
call assumed_size(b3)
contains
elemental subroutine wanted( a, b )
integer, intent(inout) :: a
integer, intent(out) :: b
a = a + 1
b = a
return
end subroutine wanted
subroutine assumed_size(b)
integer :: b(*)
call sub( a, b )
return
end subroutine assumed_size
subroutine sub( a, b )
integer, intent(inout) :: a
integer, intent(out) :: b(..)
integer :: i, j
select rank (b)
rank (0)
print *, 'scalar b'
a = a + 1
b = a
rank (1)
print *, 'rank 1 b'
do i = 1, size(b)
a = a + 1
b(i) = a
enddo
rank (2)
print *, 'rank 2 b'
do j = 1, size(b,dim=2)
do i = 1, size(b,dim=1)
a = a + 1
b(i,j) = a
enddo
enddo
rank (*)
print *, 'assumed size is unsupported'
rank default
print *, 'unsupported rank'
end select
return
end subroutine sub
end program elem
What I wanted was to write a single elemental subroutine wanted(), and then call it with the first argument always being a scalar and the second argument being a scalar or an array of arbitrary rank. The first call to wanted() in the above code is alright. However, the following three calls, which are commented out, are not allowed. If you uncomment one of them and try to compile, you will get an error like:
$ gfortran elem.f90 && a.out
elem.f90:9:17:
9 | call wanted ( a, b1 )
| 1
Error: Actual argument at (1) for INTENT(INOUT) dummy 'a' of ELEMENTAL subroutine 'wanted' is a scalar, but another actual argument is an array
This is not a gfortran bug, it is a program error, and gfortran correctly identifies the problem. Namely, only intent(in) scalar arguments are allowed to conform to arrays. In my actual application, the first argument gets changed in a complicated way; in this little example code it is just a counter that gets incremented.
In this case, what I want to happen is for the compiler to loop over the array elements, in array order, and call the elemental subroutine wanted() repeatedly (or the “as if” equivalent of that operation). So my first question is why was that limitation imposed by the language. Why not allow intent(inout) scalar arguments to conform to arrays?
Ok, so that then leads to the question of how to work around that limitation. One approach to that would be subroutine sub() in the above listing. This uses the assumed rank feature to allow the second argument to be any rank. The programmer must then account for each rank manually. I’ve done that for rank 0, 1, and 2 arguments just to show that it works. It is also possible to catch the assumed size case and treat it specially; in the above code I just write a message saying it is unsupported.
As you can see within that subroutine, what I’m doing is just looping over the array elements, in array order, and doing repeatedly what the scalar code does. So this works, but if I really wanted to support all possible ranks, up to the 15 allowed by the fortran standard, or up to 31 for the intel compiler, this would be very tedious, and it would be easy to make a typo which might result in a rare error that would be difficult to detect.
One could also write separate subroutines for each rank, and then make a generic interface for all of them. That is even more tedious and error prone, so no real advantage to that approach. It does have the advantage that unsupported ranks are detected at compile time rather than run time, so maybe that is something important.
So after my first question of why doesn’t the compiler do that for me (it would never make any of those types of mistakes, right?), my second question is whether there is a better way to handle this type of programming situation. Is there some simple and robust way to loop over all the elements of an array of arbitrary rank? Or is this clunky manual way with select rank the only option?
Is it worth trying to change the fortran standard in this situation? How often does this limitation arise for programmers? Is there some kind of ambiguity associated with the generalization of the current elemental feature?