As per object, I'm struggling understanding the logic behind functions returning allocatable arrays. I like this construct because its clarity compared to subroutines, and because pure functions in fortran are an excellent way to write clean, functional programming code.
Assume I have to write a simple function, returning an array of indices, with arbitrary bounds, such as in this program:
program test_allocatable_functionReturn
implicit none
integer, allocatable :: fun(:),sub(:),noa(:)
integer, parameter :: low = -4
integer, parameter :: hi = 3
call testsub(sub,low,hi)
fun = testfun(low,hi)
noa = testfun_noalloc(low,hi)
print '(4(a,i3),a)', 'testsub: lbound=',lbound(sub),'(expected = ',low,'), ubound=',ubound(sub),'(expected = ',hi,')'
print '(4(a,i3),a)', 'testfun: lbound=',lbound(fun),'(expected = ',low,'), ubound=',ubound(fun),'(expected = ',hi,')'
print '(4(a,i3),a)', 'no alloc: lbound=',lbound(noa),'(expected = ',low,'), ubound=',ubound(noa),'(expected = ',hi,')'
contains
pure function testfun_noalloc(low,hi) result(array)
integer, intent(in) :: low,hi
integer :: array(low:hi)
integer :: i
forall(i=low:hi) array(i) = i
end function testfun_noalloc
pure function testfun(low,hi) result(array)
integer, allocatable :: array(:)
integer, intent(in) :: low,hi
integer :: i
allocate(array(low:hi))
forall(i=low:hi) array(i) = i
end function testfun
pure subroutine testsub(array,low,hi)
integer, intent(out), allocatable :: array(:)
integer, intent(in) :: low,hi
integer :: i
allocate(array(low:hi))
forall(i=low:hi) array(i) = i
end subroutine testsub
end program
I have implemented it in three ways:
- a function returning an allocatable array (
testfun
) - a subroutine (
testsub
) - a function returning a static array (
testfun_noalloc
)
The subroutine operates on the return array, and allocates it properly. In the example, an array sized (-4:3)
should be returned. The function, in either implementation, returns an (1:hi-low+1)
-sized array:
testsub: lbound= -4(expected = -4), ubound= 3(expected = 3)
testfun: lbound= 1(expected = -4), ubound= 8(expected = 3)
no alloc: lbound= 1(expected = -4), ubound= 8(expected = 3)
Why is that happening? I get the fact that fortran may reallocate the array when assigning the function return value to my LHS array, but even so, why isn't it allocated with the proper bounds? I understand such may happen when passing the static array to an allocatable with f2003-style reallocation of the lhs, but with an allocatable array as input, I was expecting the bounds information to be conserved. Am I missing something here? BTW, this example was compiled with gfortran 9.2.0.
Thanks, Federico