Simplify the declaration of automatic arrays?

Often I want to write code that declares automatic arrays as follows:

subroutine foo(x)
real, intent(in) :: x(:)
integer          :: n = size(x)    ! not legal
real             :: a(n),b(n),c(n) ! not legal
! real             :: a(size(x)),b(size(x)),c(size(x)) ! legal but awkward
end subroutine foo

but gfortran says

size.f90:3:29:

    3 | integer          :: n = size(x)
      |                             1
Error: Assumed-shape array 'x' at (1) is not permitted in an initialization expression
size.f90:5:21:

    5 | real             :: a(size(x)),b(size(x)),c(size(x))
      |                     1
Error: Symbol 'a' at (1) already has basic type of REAL
size.f90:4:22:

    4 | real             :: a(n),b(n),c(n) ! not legal
      |                      1
Error: Variable 'n' cannot appear in the expression at (1)

Besides using the line I commented out, I know I can use ALLOCATABLE array, so that n = size(x) can appear after the declarations and n can be used to allocate the arrrays. But would it make sense to extend Fortran so that the code above works? Often when I use the current syntax

real :: a(size(x)),b(size(x)),c(size(x))

I later define n = size(x) anyway, and I wish I could have used n earlier to simplify the code.

A different compiler gives messages more closely tied to the standard text:

ftn -c test.f90

integer :: n = size(x) ! not legal
^
ftn-842 crayftn: ERROR FOO, File = test.f90, Line = 3, Column = 25
The initialization expression used on a type declaration statement must be a constant expression.

real :: a(n),b(n),c(n) ! not legal
^
ftn-521 crayftn: ERROR FOO, File = test.f90, Line = 4, Column = 23
Object “N”, used in a bounds expression must be a constant, a dummy argument, a common block member or use or host associated.

Note that this alternative does work and avoids writing size(x):

subroutine foo(x)
real, intent(in) :: x(: )
real,allocatable :: a(:),b(:),c(: )

allocate (a,b,c,mold=x)

end subroutine foo

1 Like

Initializers in Fortran are one-time static initialization, like a DATA statement. If you want to compute the value of an expression and use it to initialize a local variable on each invocation of the subprogram, you are out of luck in Fortran today. There have been proposals to extend the language with new syntax to permit dynamic initialization as part of the syntax of a declaration, so maybe you’ll be able to use C-style variable initialization sometime in the 2030’s.

Off the top of my head, two options come to mind that you can look into to alleviate the awkwardness!

First might be the simplest even if old-fashioned and that is to pass the array size as an argument

   subroutine foo(x, n)
      real, intent(in)    :: x(:)
      integer, intent(in) :: n
      real :: a(n)

Second approach is verbose but it may be worth it if the subprogram has to deal with a fair bit of different objects, perhaps in 2 or more sections of code, and whose sizes depend on the array dummy arguments. This is with more drawn out ASSOCIATE and BLOCK constructs:

   subroutine foo(x)
      real, intent(in) :: x(:)
      associate ( n => size(x) )
         block
            real :: a(n), b(n), ..
1 Like

How about the following syntax?

subroutine foo(x)
real, intent(in) :: x(:)
real, dimension(size(x)) :: a,b,c
1 Like