With fortran, I am running in situations where I have multiple local variables whose size is derived from input parameters in a somewhat verbose manner, e.g.
program pbounds
contains
subroutine sbounds(x)
integer,intent(in) :: x(:,:)
integer y1(size(x,1)/3,size(x,2)/2)
integer y2(size(x,1)/3,size(x,2)/2)
integer y3(size(x,1)/3,size(x,2)/2)
! ... do some stuff
end subroutine sbounds
end program pbounds
This seems overly verbose as I keep repeating the size expression. Additionally, when a change is needed – e.g. when it turns out that I need a y4 and change size(x,1)/3 to size(x,1)/4 – for real-world code that doesn't look quite as neat, it is easy to miss one of the previous variables.
In my real code, other examples include declarations with sizes coming from verbose, repetitive composite type fields, such as
type(sometype), intent(in) :: obj
real :: arr1(obj%subfield%nmax, obj%subfield%nmax, obj%subfield%xmax, 3, 3)
real :: arr2(obj%subfield%nmax, obj%subfield%xmax)
...
Is it possible to define a name for the size expressions, without resorting to preprocessor macros or allocatable arrays?
The things I have tried
With allocatable variables, we can use a local variable as name for the size expressions, but we split the declaration of the local arrays over two lines each.
program pboundsx
contains
subroutine sboundsx(x)
integer,intent(in) :: x(:,:)
integer,allocatable :: y1(:,:),y2(:,:),y3(:,:)
integer s(2)
s = [ size(x,1)/3, size(x,2)/2 ]
allocate(y1(s(1),s(2)))
allocate(y2(s(1),s(2)))
allocate(y3(s(1),s(2)))
! ... do some stuff
end subroutine sboundsx
end program pboundsx
With preprocessor macros we can give the size expression a name, but at the cost of adding multiple preprocessor lines, that disturb the indentation pattern among other things.
program pboundsm
contains
subroutine sboundsm(x)
integer,intent(in) :: x(:,:)
#define s1 (size(x,1)/3)
#define s2 (size(x,2)/2)
integer y1(s1,s2)
integer y2(s1,s2)
integer y3(s1,s2)
#undef s1
#undef s2
! ... do some stuff
end subroutine sboundsm
end program pboundsm
With a second subroutine we can make the sizes an explicit parameter, but this is probably the most verbose and obscure solution; even more so considering that in real-world code 'x' isn't the only parameter.
program pboundss
contains
subroutine sboundss(x)
integer, intent(in) :: x(:,:)
call sboundss2(x,size(x,1)/3,size(x,2)/2)
end subroutine sboundss
subroutine sboundss2(x,s1,s2)
integer, intent(in) :: x(:,:), s1, s2
integer y1(s1,s2), y2(s1,s2), y3(s1,s2)
end subroutine sboundss2
! ... do stuff
end program pboundss
If it was allowed to mix declarations and initialization, the solution would be simple – but it is not:
program pboundsv
contains
subroutine sboundsv(x)
integer,intent(in) :: x(:,:)
integer s1 = size(x,1)/3, s2 = size(x,2)/3 ! INVALID DECLARATION
integer y1(s1,s2), y2(s1,s2), y3(s1,s2)
! ... do stuff
end subroutine sboundsv
end program pboundsv
integer, dimension(expr) :: y1, y2, ...?