4

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

roygvib
  • 7,218
  • 2
  • 19
  • 36
  • Hi, @roygvib, I test your code with `ctrl+F5` under release mode within ifort+vs2013, but the last two lines of results: `a(:) = 1 a(:) = 1 2 ` didn't show up. Did you compile your code under some special mode? (I don't quite get the purpose of option `-assume` and `realloc_lhs` ) – zlqs1985 Nov 25 '16 at 03:24
  • @zlqs1985 I think this is because of two reasons: (1) The lines `a = [ a, 1 ]` and `a = [ a, 2 ]` perform so-called "automatic reallocation" (a recent feature in Fortran), which does allocate() implicitly on the array of the left-hand side when the array size is different from the right-hand side. (For example, in the case of a = [ a, 1 ], the right-hand side is a 1-element array and we try to assign it to `a`. Because the original `a` has no element (size 0), we need to deallocate()/allocate() `a` if we use Fortran90, but with this new syntax it is re-allocateed automatically to correct size. – roygvib Nov 27 '16 at 02:04
  • (2) For some reason, gfortran supports this feature by default, while Intel fortran did not employ it as default (probably to keep consistency with older codes). So, to enable that feature in ifort, we need to attach the option `-assume realloc_lhs` (or `-standard-semantics`) explicitly. AFAIK, we need this option up to Intel Fortran 16. But from ifort-2017, this option becomes the default, so the above code works without any option (probably). --- Sorry for my poor explanations, and if you need more information, please consider posting a new Question (I guess you will get more solid info :) – roygvib Nov 27 '16 at 02:18
  • To summarize, yes, I compiled the code with `-assume realloc_lhs` in the case of ifort because I used ifort-14 at that time. (On the other hand, I did not attach any option for gfortran.) – roygvib Nov 27 '16 at 02:19

2 Answers2

9

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

High Performance Mark
  • 77,191
  • 7
  • 105
  • 161
  • By "empty array constructor" you mean, say `a=[]` rather than `a=[integer::]`? I may have done you an injustice in my answer if you did. – francescalus Feb 07 '16 at 12:58
  • Thanks very much for your explanation. I had never tried allocation of 0-sized arrays before, so I was not very sure if this was really OK. As for `a(:)` in my second question, I tried to refer to the allocatable array itself, so I should have written `a` rather than `a(:)` in my question... (I am sorry about this!) My question was whether I can safely omit `allocate( a(0) )` by relying on compilers' initialization, but this seems not good according to your (and @francescalus') answers. I will then allocate them explicitly. Thanks :) – roygvib Feb 07 '16 at 14:42
4

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
francescalus
  • 30,576
  • 16
  • 61
  • 96
  • Thank you very much for your answer. Yes, if I write `a = []`, the RHS does not have any type information, so it seemed reasonable to me that it becomes an error, but I wondered why `a = [integer::]` was also an error... (but in fact it was valid!) As for `allocate( a(0) )`, all of GNU, Intel, and Oracle compilers gave correct results even without explicit allocation, but relying on this (using unallocated arrays) is probably a bad practice so I should avoid... – roygvib Feb 07 '16 at 15:10
  • Using `[a,1]` when `a` is not allocated certainly is bad practice: you have a non-compliant program. Of course, that leaves the compiler open to do whatever it likes and it may well reliably treat it as though a zero-sized array were being used. It won't be portable, though, and even changing compilation options (say adding bounds or memory access checking) may result in termination instead. – francescalus Feb 07 '16 at 15:19