Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

  • First of all, is it OK to allocate zero-sized arrays such as allocate( a( 0 ) )?
  • If we omit such an explicit allocation, will a(:) be automatically initialized to a zero-sized array? (Indeed, the code seems to work even if I comment out Line 1.)
  • Is it no problem to include zero-sized arrays in an array constructor like a = [a, 1]? (I also tried using an empty array constructor like a = [] or a = [integer::], but they did not compile and so seem to be not allowed.)

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).

like image 267
roygvib Avatar asked Dec 14 '22 08:12

roygvib


2 Answers

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

like image 173
High Performance Mark Avatar answered Mar 16 '23 13:03

High Performance Mark


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
like image 35
francescalus Avatar answered Mar 16 '23 12:03

francescalus