Read data and append it to array, best practice?

Because this syntax defines an array of allocatable characters, which is not allowed.

@RonShepard , @PierU
In what sense is my approach not allowed? Can it cause data loss or memory leaks?
Thank you

If you write out the array elements individually, then it is allowed. The implied do-loop is a little more concise (more so for longer arrays), and it is also allowed. What isn’t allowed is my last suggestion with array notation stra%sa(:)%s.

My poorly phrased question was not why it was not allowed according to the standard, I understand that; my question is why the standard is so restrictive in this case and does not allow it. The standard might disallow the syntax because it is ambiguous in some logical way, or because using it might be difficult for compilers to understand, or it might be difficult for humans to understand. Another reason is that the syntax might be set aside and effectively “reserved” for some future version of the standard where it might mean something entirely different. None of those things seem to apply here.

So why does the standard not allow the simple array notation in this case?

BTW, the other possibility when using strings is to have an array of the derived type, rather than a derived type with an array. Here is a modification of the original code above that demonstrates this other approach.

program xxx
   implicit none
   type string
      character(:), allocatable :: s
   end type string
   type string_array
      type(string), allocatable :: sa(:)
   end type string_array

   integer :: i
   type(string) :: sfoo
   type(string), allocatable :: str(:)
   type(string_array) :: stra

   allocate(stra%sa(2))
   stra%sa(1)%s = 'asd'
   stra%sa(2)%s = 'fghi'
   sfoo%s ='qwerty'
   stra%sa = [stra%sa,sfoo]
   print *, stra%sa(1)%s//stra%sa(2)%s//stra%sa(3)%s

   allocate( str(2) )
   str(1) = stra%sa(1)
   str(2) = stra%sa(2)
   str = [str, stra%sa(3)]
   print *, (str(i)%s, i=1,3)
   !print *, str(:)%s      ! not allowed
end program xxx

That last print statement that is commented out is not allowed by the standard. It has always seemed to me like it should be.

I have actually given the reason above:

More precisely an array of allocatable characters is not allowed because each element can have a different storage size, which would mean a non constant stride.

This is true (and also for pointer components), but the nonconstant stride has nothing to do with the semantic meaning of the array expression str(:)%s. If the component s is a fixed size (or a parametrized size, which is somewhere between fixed and variable), then it would be constant stride, and if the component s is an allocatable or a pointer, then it would have a nonconstant stride between elements. The expression could be defined to have the same semantic meaning as str(1)%s,str(2)%s,str(3)%s or as (str(i)%s, i=1,3), both of which are allowed in the standard, but are not as concise, not as clear, and are more error prone than the array expression.

I don’t get that… The non-constant stride is the reason why str(:)%s is not allowed.

This syntax defines an array, it would stange and non consistent if it was sometimes an array, and sometimes an i/o list.

My current thinking is that str(:)%s is not just an expression but (syntactically) a designator (if it wasn’t for the C919 constraint “A part-name to the right of a part-ref with nonzero rank shall not have the ALLOCATABLE or POINTER attribute”).

That means that it can be used in a variable definition context, e.g. str(:)%s = x, or call f(str(:)%s) where the dummy of f is Intent(Out) or Intent(InOut).

I think that’s the kind of thing the Standard has always avoided with the restriction on vector-subscripts in actual arguments corresponding to Intent(Out) dummies.

1 Like

Good point. Another possible way to write that i/o list would be with vector subscripts: str([1,2,3])%s. That syntax is not allowed either, although the programmer’s intent would be perfectly clear, and the compiler could parse and implement it in a straightforward way if it were allowed.

That seems like a circular argument since the extension to nonconstant stride cases is exactly what we are discussing. I certainly agree that the compiler might want to implement the nonconstant stride cases differently than the constant stride cases, but I still think that is not a good reason to exclude the nonconstant stride cases as part of the legitimate syntax in the language. If the compiler can understand the implied do loop syntax (or an explicit do syntax, for that matter), then it could understand the equivalent array syntax.

In this context, I would say that str(:) is an array, while str(:)%s is a sequence of array element components. To me, it is now “strange and non consistent” to disallow that sequence of array element components to be specified with array syntax.

The thinking seems to be “let simple syntax describe simple operations”. I appreciate that this is not aligned with contemporary preferences but the Fortran game is a long one and the fashion for cramming complicated things in simple syntax may pass.

1 Like

That’s the whole point: str(:)%s is as much an array as str(:), with all bells and whistles of Fortran arrays (which includes a constant stride). It’s not a “sequence of array elements”.