The issue here is whether it was strict f90/f95, or whether some or all of the allocatable TR was implemented. In hindsight, this was a mistake by the f95 standards committee. Both the f95 standard and the allocatable TR were done at the same time. There should have been better communications between the various members of the committee regarding that timing, and the f95 standard should have included the contents of the TR, even it it would have required a delay of a few weeks. As it played out, there would not be another standard update for almost 10 years (f2003, which of course was not available until 2005 or so). In that decade, so-called f95 compilers adopted different subsets of the TR features. I think the standard committee was expecting to produce a new revision in the 1998 timeframe, which would have addressed this problem sooner, but that didn’t happen.
The strict f90/f95 treatment of allocatable arrays was very limited. I remember during that time resorting often to using pointers rather than allocatables in order to have portable, lowest common denominator, code. Even compilers that claimed to support the TR often had missing features, so it was difficult to find even the common subset of code that used TR features that would work on several compilers.
I don’t know, but I expect it did. There was about a 10 year gap in between. Allocate on assignment might be such a feature that was not in the TR but was in f2003, but I’m not sure. Another one was allocatable scalars. I remember having to allocate derived type arrays of size 1 when all I really wanted was a scalar entity. After f2003 features became more common, I went back and changed a bunch of those.
Compiler engineer Peter Klausler has kindly provided some examples that help to clarify some behavior that was described incorrectly in this thread. See
I’m not sure the second one can refute the claim that a compiler may reallocate even if the destination shapes fit: only a loc() could show that it happens, and even if it doesn’t in the example this is not a proof that the standard prohibits this behavior.
This second example is interesting, though, as it shows the some compilers do not apply correctly the lower bound rules in all cases.
The comments in the code in that second example also claim:
! The conditions in which an allocated left-hand side
! allocatable is reallocated are very clearly specified in the standards
! since F'2003.
I do not think that is correct. The situation where the LHS is previously allocated to be the correct shape and bounds is ambiguous. It is unclear if this ambiguity is on purpose (to intentionally allow the compiler to optimize) or if it is unintentional.
I hope this thread demonstrates that the rules of using lower bounds other than 1 are sufficiently complicated that people disagree on whether the rules are even clear and it takes quite a lot of discussion to clarify the rules.
I suspect we all adopt certain habits and we understand how the rules apply within those habits. We then construct a mental map of how to navigate the language and what the language means, but if we enter new territory by doing something outside those habits or if someone new edits the code with different habits, it sometimes invalidates our mental map. None of this negates the fact that lower bounds other than 1 feel most natural for certain algorithms. I’m using a lower bound of 0 in code that I inherited and have developed a new set of habits that seem to be working, but I’m very tempted to refactor the code at some point to switch to a lower bound of 1. We’ll see if I ever get around to it…
Good catch with the standardese around array dimensions that have nonzero extents where the LBOUND result will be based on the lower bound of the array. However, a zero-sized array will have one or more dimensions with zero extents and the LBOUND along those dimensions will be 1:
So please see above where an attempt is made to address the charge of misinformation. Perhaps you will run this by the compiler engineer and see if the correction is still misinformation, or if the standard still has more nuances and complications to offer here.
The rules are not that complicated. The only ambiguous point so far is whether allocation on assignment can occur or not when the shapes match, with the possible consequences on the bounds.
Three cases where I’ve found non-default lower bounds useful:
sparse matrices; some solver libraries expect zero-based indexing. E.g. for a CSR matrix, one can use:
integer :: ia(0:n), ja(0:nnz-1)
for the row and column indexes.
Halo regions, as already mentioned. I did encounter some surprises here when passing such arrays to subroutines, particularly in the case where the number of halo cells is dynamic.
Various tables, where properties could be mapped naturally to a range. (For example the properties of moist air in the range between 20 and 100 degrees Celsius)
Michael Wirth has written the following about custom bounds:
In addition, Fortran arrays can be indexed using any starting value, making an the language conform to the algorithm, rather than the other way around (and if you really like arrays that start at zero, you can use them). For anyone looking for a good example of an algorithm that uses negative array indices, look no further than Niklaus Wirth’s classic 8-Queens problem.