It occurred to me that the POS restriction for formatted stream might also be related to the ENCODING value in the OPEN statement. I have only experimented with this feature a little, but there are other discussions here about how it works, and the external file could be filled, for example, with variable-length characters. The only way to be sure that a POS value is not in the middle of a variable length character would be for that value to be returned by INQUIRE after it had been positioned correctly by a previous READ or WRITE statement. This is also consistent with the fact that INQUIRE(...IOLENGTH=...) only works for unformatted, not formatted, files, so there is no separate way (that I know of) to determine file storage units associated with an external file with variable length characters.
I was curious what exactly the consequences are for this, so I experimented a little with status='replace' in the open statement with this short program.
program replace
integer :: n=10
open(n,file='replace.dat',status='replace')
write(n,'(i0)') n
end program replace
$ gfortran replace.f90
$ a.out && ls -i replace.dat
25089019 replace.dat
$ a.out && ls -i replace.dat
25089019 replace.dat
$ a.out && ls -i replace.dat
25089019 replace.dat
$ flang replace.f90
$ a.out && ls -i replace.dat
25089019 replace.dat
$ a.out && ls -i replace.dat
25089019 replace.dat
$ a.out && ls -i replace.dat
25089019 replace.dat
$ nagfor replace.f90
NAG Fortran Compiler Release 7.2(Shin-Urayasu) Build 7203
[NAG Fortran Compiler normal termination]
$ a.out && ls -i replace.dat
25088954 replace.dat
$ a.out && ls -i replace.dat
25088956 replace.dat
$ a.out && ls -i replace.dat
25088958 replace.dat
This is with MacOS. With both the gfortran and flang compilers, the same inode was displayed for the file after repeated runs. This was “as if” the old file were accessed and overwritten, which is what happens with status='old' in the open statement. With the nagfor compiler, each run created a new file with a new inode.
I think the nagfor compiler behavior matches the fortran standard description, and the other two compilers are incorrect. I was wondering what consequences this might have. As far as fortran is concerned, I could not think of any, but there are consequences outside of fortran. Just one example, hard links (ln on unix/posix machines) allow several file names to be associated with a single file (i.e. several file names that all have the same inode). The nagfor code would behave differently than the gfortran and flang codes in these cases. I guess there might be other consequences too, such as how file backups of the file system behave, or maybe utilities like make would behave differently since the other file names would appear to have been modified [edit] with gfortran and flang, but not with nagfor. Is this serious enough to file bug reports with gfortran and flang?
How do other OS and compiler combinations behave for status='replace' in the open statement?
It’s no surprise that NAG matches the standard word for word. But I wouldn’t say the behavior of the other two compilers is incorrect —it’s just an implementation detail.
If I’m in a terminal, and want to empty a file, I issue truncate -s 0 instead of rm followed by touch. Those compilers’ runtimes are just doing the equivalent syscall, since historically the cost of actual deletion followed by creation could have been huge —SSD and CoW filesystems are just a recent thing .
Maybe there are consequences on Windows?.. but since on POSIX systems removing a file is actually an unlink call —i.e., a named file is actually a hard link to some underlying block(s), and by deleting you just remove the link, but the underlying data is still there, so other files that have hard links to said data are unaffected.
I just checked on Debian, with btrfs as the filesystem (which loves creating blocks whenever possible), and the behavior with gfortran, ifx, flang-new and nvfortran is similar to the one you showed.
I guess it is the opposite. As you report, gfortran and flang keep the inode number, thus they truncate the hardlinked file in-place, so all instances will show the new modification time. If nagfor really deletes the file (cutting the link) and recreates it with a new inode number, the other, remaining hardlinked instances will show the file unchanged.
Some compilers differentiate between formatted or unformatted stream access files when implementing truncate.
I think this relates to prervious non-standard support for stream like access files where truncate can be auto applied to formatted files, but not unformatted/binary files.