roygvib
roygvib

Reputation: 7385

Allocation of zero-sized arrays and use in array constructors

In the following code, I am trying to allocate an empty array of size 0 and add more elements afterward by using automatic reallocation:

integer, allocatable :: a(:)

allocate( a(0) )        ! Line 1
print *, size( a )
print *, "a(:) = ", a

a = [ a, 1 ]
print *, "a(:) = ", a

a = [ a, 2 ]
print *, "a(:) = ", a

!! Error
! a = []
! a = [ integer :: ]

This code gives the expected result (e.g., with gfortran or ifort -assume realloc_lhs)

           0
 a(:) = 
 a(:) =            1
 a(:) =            1           2

Here I have three questions:

Edit

If I uncomment a = [] in the above code, gfortran5.3 gives the error message:

Error: Empty array constructor at (1) is not allowed

but if I uncomment only the line a = [ integer :: ], it worked with no problem! Because I initially uncommented both lines at the same time, I misunderstood that the both ways are illegal, but actually the latter seems OK (please see @francescalus answer).

Upvotes: 5

Views: 8284

Answers (2)

francescalus
francescalus

Reputation: 32366

High Performance Mark's answer covers much of this, but there is more to add (or restate in a different way). Regarding whether a is "initialized to a zero-sized array", it isn't and you can see more detail in another question. Note, in particular that a is initially undefined (and unallocated).

As your other answer states, a(:) is an array section and it cannot be automatically allocated on intrinsic assignment. It's perhaps worth noting that this is because a(:) does not have the allocatable attribute. This has other effects, such as not allowing it to be associated with a dummy argument with that attribute.

At a high level, yes, zero-sized arrays are fine (again, see the linked question where there is a meaningful difference between zero-sized and unallocated). Your approach with that allocate statement and use in a subsequent array constructor are entirely reasonable.

In particular, though, to support High Performance Mark's answer, use of an unallocated array in the array constructor is not permitted: an unallocated variable may not be referenced.

Coming to construction of a zero-sized array: zero-sized arrays may be constructed, and there is nothing special about a zero-sized array being used in intrinsic assignment to an allocatable variable.

When an array is constructed the type (and type parameters) of the array must be known. With an array constructor such as [a,1] (assuming a is integer of default kind) this array is integer of default kind. How can a compiler know the type/parameters of []?

It can't, which is why the syntax for an array constructor for a zero-sized array is as you have it: [integer::] is an array constructor for a (rank-1) zero-sized array of integer of default kind.

In Fortran 2008 you can see this syntax as R468, R469 (4.8), and similar can be found in Fortran 2003.

Finally, there is another way for a zero-sized array constructor:

integer i
print*, [(i, i=1,0)]
end

Upvotes: 4

High Performance Mark
High Performance Mark

Reputation: 78316

1 Yes. Fortran is cool with 0-sized arrays.

2 a(:) is not an array but an array-section (albeit one which comprises the whole array). Automatic reallocation is not defined to work on array sections, so

allocate(a(0))
a(:) = [1 2 3]

doesn't work. In my test the code compiled and executed but a was left with 0 size.

As to whether the code a = [a,1] ought to work if a has not previously been allocated (to 0- or any other size) my reading of the standard is that this is not standard conforming and that your compiler (mine too) is in error. I expect this is a mis-reading of the standard on my part. Perhaps someone else will come along and explain properly.

3 Yes

allocate(a(0))
a = [a, 1]

is fine, it conforms to the standard and works as you'd expect. As you've noticed an empty array constructor is not permitted in an automatic allocation

Upvotes: 10

Related Questions