experchange > fortran

Thomas Koenig (02-03-19, 01:23 PM)
Hi,

I don't think allocating an already allocatable variable makes
a lot sense, and gfortran rejects it.

However, I cannot find anything in the standard that actively
prohibits

real, allocatable, dimension(:) :: a
allocate (a(10))
allocate (a(20))

or tells me anything about what the program

real, allocatable, dimension(:) :: a
integer :: istat
allocate (a(10))
allocate (a(20),stat=istat)
print *,size(a)
end

should do or print. Ideas?
rbader (02-03-19, 02:08 PM)
Am Sonntag, 3. Februar 2019 12:23:05 UTC+1 schrieb Thomas Koenig:
[..]
> print *,size(a)
> end
> should do or print. Ideas?


According to 9.7.1.3 (para 1, first bullet) of F2018, both programs are non-comforming, and the stat value on the second allocation must return a non-zero value.
Regards
Reinhold
Beliavsky (02-03-19, 02:28 PM)
On Sunday, February 3, 2019 at 6:23:05 AM UTC-5, Thomas Koenig wrote:
[..]
> print *,size(a)
> end
> should do or print. Ideas?


In Fortran 2003+, you can use allocation upon assignment of an ALLOCATED variable to reallocate a variable, but you cannot use the ALLOCATE statement to do so. See the program below. I think this is an inconsistency of the language, but the committee must have some reason for maintaining it.

program xalloc
implicit none
integer, allocatable :: ivec(:)
ivec = [2]
print*,ivec
ivec = [2,4]
print*,ivec
deallocate(ivec)
allocate(ivec(2))
ivec = [3,6]
print*,ivec
allocate(ivec(3))
ivec = [3,6,9]
print*,ivec
end program xalloc

Compiling and running with GNU Fortran (GCC) 9.0.1 20190127 (experimental) from equation.com on Windows 10 gives output

2
2 4
3 6
At line 12 of file xalloc.f90
Fortran runtime error: Attempting to allocate already allocated variable 'ivec'

The program runs to completion if you add the line

deallocate(ivec)

before

allocate(ivec(3))
Thomas Koenig (02-03-19, 03:10 PM)
rbader <Bader> schrieb:
> Am Sonntag, 3. Februar 2019 12:23:05 UTC+1 schrieb Thomas Koenig:
> According to 9.7.1.3 (para 1, first bullet) of F2018, both
> programs are non-comforming, and the stat value on the second
> allocation must return a non-zero value.


I read that paragraph before, but somehow did not see the
relevant sentence:

# An allocatable variable with this status may be referenced,
# defined, or deallocated; allocating it causes an error condition
# in the ALLOCATE statement.

However, I have also found

9.7.4 STAT= specifier

[...]

6 [...] If any other error condition occurs, each
allocate-object has a processor-dependent status:

[...]

* each allocate-object that was not successfully allocated or
deallocated shall retain its previous allocation status or
pointer association status.

From this, it seems that the second program is valid, and should
print 10. Or is there something in the sentences above (like "error
condition" or "processor-dependent") that changes the meaning?
rbader (02-03-19, 03:52 PM)
Am Sonntag, 3. Februar 2019 14:10:59 UTC+1 schrieb Thomas Koenig:
[..]
> From this, it seems that the second program is valid, and should
> print 10. Or is there something in the sentences above (like "error
> condition" or "processor-dependent") that changes the meaning?


I think you are right; the second program is conforming because it specifies the stat and therefore continues execution and preserves the allocation status of the previously allocated entity.
FortranFan (02-03-19, 04:24 PM)
On Sunday, February 3, 2019 at 8:52:52 AM UTC-5, rbader wrote:

> ..
> I think you are right; the second program is conforming because it specifies the stat and therefore continues execution and preserves the allocation status of the previously allocated entity.


For whatever it's worth, I think so too. And gfortran also appears to process the instructions in a conforming manner. The following slight variant of the second program generates the output shown below which is what I expect per the standard:

real, allocatable, dimension(:) :: a
integer :: istat
character(len=256) :: amsg
allocate (a(10))
allocate (a(20),stat=istat,errmsg=amsg)
print *, "Following 2nd allocation: stat = ", istat, ", ", trim(amsg)
print *,size(a)
end

Upon execution with gfortran,

Following 2nd allocation: stat = 5014 , Attempt to allocate an allocated object
10
Ron Shepard (02-03-19, 08:50 PM)
On 2/3/19 6:28 AM, Beliavsky wrote:
> In Fortran 2003+, you can use allocation upon assignment of an ALLOCATED variable to reallocate a variable, but you cannot use the ALLOCATE statement to do so. See the program below. I think this is an inconsistency of the language, but the committee must have some reason for maintaining it.


The need for a conditional allocation is very common.

! conditional allocation of x(n)
qalloc = .true.
if ( allocated(x) ) then
if ( size(x) == n ) then
qalloc = .false.
else
deallocate(x)
endif
endif
if ( qalloc ) allocate(x(n))

This functionality could easily be added to the language with either a
separate allocate() kind of statement or with a flag to the existing
allocate() statement.

The allocation upon assignment has been problematic since it was
introduced to the language in f2003. As far as performance, it is like
loading a gun, pointing it at your foot, putting your finger on the
trigger, squeezing it just a little, and then hoping everything turns
out alright. Some of us would rather not do all of those things, but the
way it was introduced into the syntax, there is little choice. To be
fair, I'm not sure of a better syntax, but nonetheless, it has been and
is a problem as it is now.

Even now, over a decade after it became available in compilers, I'm
still adding (:) (and (:,:), etc.) to the left hand sides of array
statements in legacy code in order to avoid false positive compiler
warnings and to allow runtime checks for mismatched array statements,
checks that came for free before f2003.

$.02 -Ron Shepard
Steve Lionel (02-04-19, 12:22 AM)
On 2/3/2019 7:28 AM, Beliavsky wrote:
> In Fortran 2003+, you can use allocation upon assignment of an ALLOCATED variable to reallocate a variable, but you cannot use the ALLOCATE statement to do so. See the program below. I think this is an inconsistency of the language, but the committee must have some reason for maintaining it.


I don't think it's inconsistent at all. Intrinsic assignment to an
allocatable first deallocates if the shapes or length parameters don't
match. If they do match, there is no reallocation, otherwise the
variable is allocated to a shape and length matching the expression.
This is what programmers intuitively expect from an assignment.

An ALLOCATE statement says "allocate me". Not, "maybe reallocate me if
my shape is different." While I could imagine ALLOCATE being extended in
this manner, I see no convincing motivation to do so.
spectrum (02-04-19, 02:48 PM)
On Monday, February 4, 2019 at 3:50:32 AM UTC+9, Ron Shepard wrote:
[..]
> This functionality could easily be added to the language with either a
> separate allocate() kind of statement or with a flag to the existing
> allocate() statement.


I also think that this pattern occurs pretty commonly. Indeed, I have
such routines in my programs (for 1d, 2d, 3d, and for integer and
double precision) exactly for this purpose (to make the coding simpler).

I guess such routines would not be necessary if the above procedure
can be performed simply as resize( a( n ) ) etc with a builtin method.
AFAIK, I think pretty many languages support this feature (I will check them
if necessary).

Similarly, allocatable 1-d arrays are still missing append() or push() for
adding new elements. For this reason, one often needs to
use additional variables/counters for book-keeping purpose.

In short, Fortran is very strong for rectangular data (and for high performance),
while it becomes much weaker for handling irregular/unstructured data (just my
impression).

[..]
> statements in legacy code in order to avoid false positive compiler
> warnings and to allow runtime checks for mismatched array statements,
> checks that came for free before f2003.


I also feel that this syntax is pretty dangerous, so I put (:) always on the LHS
(except for small trivial codes).

If "inconsistency" exists, I feel it is the "gap" between the automatic reallocation above
and the lack of resize()/append() etc. The former is more common in a dynamically typed
language (so one needs to be very careful about rebinding and mutation of LHS),
while I feel the latter are more "basic" things (but still missing).

(But of course, my opinion above is biased with my experiences <-- i.e., almost no
usage of automatic reallocation in actual codes.)
spectrum (02-04-19, 02:54 PM)
Hmm, I'm sorry, the following part is a bit strange, so please ignore...

> The former is more common in a dynamically typed language ... (but still missing).


# I just remembered the distinction between a = b and a[:] = b in other languages,
which have different semantics (and so the user needs to be very careful).
gah4 (02-04-19, 04:20 PM)
On Sunday, February 3, 2019 at 2:22:51 PM UTC-8, Steve Lionel wrote:
> On 2/3/2019 7:28 AM, Beliavsky wrote:
> > In Fortran 2003+, you can use allocation upon assignment of an
> > ALLOCATED variable to reallocate a variable, but you cannot use
> > the ALLOCATE statement to do so. See the program below.
> > I think this is an inconsistency of the language, but the
> > committee must have some reason for maintaining it.


> I don't think it's inconsistent at all. Intrinsic assignment to an
> allocatable first deallocates if the shapes or length parameters don't
> match. If they do match, there is no reallocation, otherwise the
> variable is allocated to a shape and length matching the expression.
> This is what programmers intuitively expect from an assignment.


Not complaining about ALLOCATE, but "allocate on assignment"
is not something programmers intuitively expect.

Fortran has a long history of not doing bounds checks, trusting
programmers to get it right. This pretty much requires the compiler
to do bounds checking (unless it can determine at compile time it
isn't needed). It is a little late now, but a REALLOCATABLE
attribute, requesting allocate on assignment, might have been
nice, and only two more letters. Also, allocate on assignment
could make debugging harder, as it makes it harder to follow, when
looking for allocations.

> An ALLOCATE statement says "allocate me". Not, "maybe reallocate me if
> my shape is different." While I could imagine ALLOCATE being extended in
> this manner, I see no convincing motivation to do so.


I suppose a REALLOCATE statement might be nice, requesting such.

C's realloc() has the advantage of allowing reallocation in place
when the OS can do it, but otherwise a copy is done. A way to request
that in Fortran might be nice.

Otherwise, for comparison purposes only, in PL/I, ALLOCATE stacks
allocation if you use it on an already allocated variable. I presume
this is useful in some recursive routines.
FortranFan (02-04-19, 05:20 PM)
On Sunday, February 3, 2019 at 1:50:32 PM UTC-5, Ron Shepard wrote:

[..]
> This functionality could easily be added to the language with either a
> separate allocate() kind of statement or with a flag to the existing
> allocate() statement.


Can @Ron Shepard present a minimal working example (MWE) illustrating the issue of "The need for a conditional allocation is very common"? Otherwise the comment appears inaccurate with current conforming compilers and the code snippet shown above appears entirely unnecessary given the current standard.

> The allocation upon assignment has been problematic since it was
> introduced to the language in f2003. As far as performance, it is like
> loading a gun, pointing it at your foot, putting your finger on the
> trigger, squeezing it just a little, and then hoping everything turns
> out alright. Some of us would rather not do all of those things, but the
> way it was introduced into the syntax, there is little choice. To be
> fair, I'm not sure of a better syntax, but nonetheless, it has been and
> is a problem as it is now.


Again, this sounds inaccurate with respect to *current* conforming compilerversions.
> Even now, over a decade after it became available in compilers, I'm
> still adding (:) (and (:,:), etc.) to the left hand sides of array
> statements in legacy code in order to avoid false positive compiler
> warnings and to allow runtime checks for mismatched array statements,
> checks that came for free before f2003.
> ..


The relevant question here is whether such "legacy code" conformed to any standard revision, Fortran 90 or 95, in the first place. Again, a MWE illustrating the need that results in "adding (:) (and (:,:), etc.) to the left hand sides of array statements" is something will be very useful. In the absence of actual code reproducers that clearly show the problems with allocate-on-assignment feature from the current standard as implemented in conforming compilers that are employed toward *legacy code*, the argument here is questionable.
FortranFan (02-04-19, 05:30 PM)
On Monday, February 4, 2019 at 7:48:15 AM UTC-5, spectrum wrote:

> ..
> I also think that this pattern occurs pretty commonly. Indeed, I have
> such routines in my programs (for 1d, 2d, 3d, and for integer and
> double precision) exactly for this purpose (to make the coding simpler).


@spectrum,

Are you referring here to the code snippet with the conditional allocation using 'qalloc' object of logical type? Or the bit about "adding (:) (and (:,:), etc.) to the left hand sides of array statements"?
spectrum (02-04-19, 05:59 PM)
On Tuesday, February 5, 2019 at 12:31:00 AM UTC+9, FortranFan wrote:

> Are you referring here to the code snippet with the conditional allocation using 'qalloc' object of logical type? Or the bit about "adding (:) (and (:,:), etc.) to the left hand sides of array statements"?


In my case, I mean the "qalloc" example in Ron's example (which I refer as resize() etc).

RE automatic allocation of LHS, I've used the word "dangerous", but I'm afraid
this word may have been too strong (I have no intention to offend the current standard or
the efforts around this syntax). What I mean is that the user needs to be more careful
about the meaning of "=" than previously, because it has now dual meaning of copy and
possible reallocation.

On the other hand, I'm not sure whether this "=" really induces some overhead in
practice. Because recent compilers are very strong about optimization, my (wild) guess
is there is essentially no performance penalty -- but I'm not sure because
I've never measured the performance difference for it.

My another question is how this automatic reallocation of LHS syntax has been
introduced or what motivated its introduction. Maybe Matlab-inspired...?
FortranFan (02-04-19, 07:36 PM)
On Monday, February 4, 2019 at 10:59:46 AM UTC-5, spectrum wrote:

> ..
> In my case, I mean the "qalloc" example in Ron's example (which I refer as resize() etc).


If one has certain specific requirements (say the code needs to conform to a given Fortran standard revision e.g., Fortran 90; or it needs to work with a processor that does *not* conform to current standard, etc.), then ok one may need such "resize() code". In that case though, one should qualify one's statements with one's needs. Because otherwise with the current standard and growing list of conforming processors, the code shown by @Ron Shepard with 'qalloc' is unnecessary and the comment about the need being 'common' is misleading, it's a disservice to readers.

> RE automatic allocation of LHS, I've used the word "dangerous", but I'm afraid
> this word may have been too strong (I have no intention to offend the current standard or
> the efforts around this syntax). What I mean is that the user needs to bemore careful
> about the meaning of "=" than previously, because it has now dual meaning of copy and
> possible reallocation.
> ..


Yes, I do think the word 'dangerous' is a misrepresentation. Such a term must place the burden on those raising such alarms to better illustrate theissues, as in how the feature enhancement starting with Fortran 2003 with allocate upon assignment makes things 'dangerous' compared to how it was with the earlier revision.

Consider Fortran 95 revision: section 7.5.1.4 Intrinsic assignment conformance rules states, "For an intrinsic assignment statement, variable and exprshall conform in shape, and if expr is an array, variable shall also be anarray"; Fortran 90 was the same. Legacy code that conforms to Fortran 90/95 standard will face no more "danger" with later revisions during intrinsic assignments involving arrays.

As I wrote earlier, chances appear more likely the "legacy code" mentioned by @Ron Shepard was non-conforming to begin with and it could be the resulting "correction" attempt to get such code to work with improved present-dayprocessors that involved "adding (:) (and (:,:), etc.) to the left hand sides of array statements". In that case there are likely better code refactoring options. Again @Ron Shepard or whoever is commenting about these problems should present *minimal working examples" with standard-conforming code to back up these alarms about problems.

Similar Threads