NEWUNIT specifier value vs. Standard

F2018 standard in “Referring to a file” section (12.5.1) specifies:

2 A unit is either an external unit or an internal unit. An external unit is used to refer to an external file and is specified by an asterisk or a file-unit-number. The value of file-unit-number shall be nonnegative, equal to one of the named constants INPUT_UNIT, OUTPUT_UNIT, or ERROR_UNIT of the intrinsic module ISO_FORTRAN_ENV (16.10.2), the unit argument of an active defined input/output procedure (12.6.4.8), or a NEWUNIT value (12.5.6.12).

In the section describing NEWUNIT= specifier in OPEN statement (12.5.6.12), however, it explicitly states that

3 A NEWUNIT value is a negative number, and shall not be equal to −1, […]

I find these two statements contradictory, as it cannot be nonnegative and negative at the same time.

Do I miss something here?

The clauses separated by commas are OR’ed, not AND’ed.

1 Like

It is not very precise, though. Confusion may grow if one checks the MFE (2018) book, where one finds (Section 10.5, Unit Numbers):

[…] and each unit, with two exceptions, has associated with it a unit number. This number must not be negative.

(the exceptions being read fmt, I/O_list and print fmt, I/O_list). And just a bit later:

A scalar integer expression that gives the unit number: […]
where the value may be any non-negative integer allowed by the system for this purpose

My understanding is that all external units (i.e. reading from or writing to a file or the terminal) are positive and all internal units (i.e. reading from or writing to a character variable) are negative. User defined derived type IO (UDDTIO) is really the only reason the later need be specified, as no unit number ever appears for reading from or writing to character variables in any other case. In all other cases the unit number in a read, write, close or maybe a couple other statements must be a positive integer associated with an already connected “file”. Thus, newunit should always be set to a positive integer not already associated with any other connected “file”.

In implementation all the compilers I know of only allow a user to use a positive value they select on an OPEN UNIT=, and always return a negative value not equal to -1 when NEWUNIT is used on the OPEN, and internally manage tracking all the negative values so they can get a unique one. The oddest side-effect is if you open a file without a name that was opened with OPEN(NEWUNIT=… it generally creates a filename like “fort.-10”. Opening a non-scratch file without a name is non-standard, but every compiler does it. Last I looked it broke some extensions some compilers had for using environment variables to control such “unnamed” files’ names, but was not much of a problem. That implies that something is tracking all the files opened with NEWUNIT= internally. It would be a nice feature if Fortran let you do a query and get back all opened files, even if only those opened with NEWUNIT=. So at least in practice all LUNs you assign are positive and all LUNs returned by Fortran from using NEWUNIT= are negative. It broke some old code that used to change the sign of the LUN to indicate the file was not currently open in some old codes but has not been a problem since, except a few hold-outs that like opening unnamed files who will not switch to using NEWUNIT= because of the filenames with the minus in them that it causes with a lot of compilers. -1 got saved as a magic number; probably to accomodate some of that old usage but not sure.

I don’t see any confusion here. As @themos says, it’s an “or” list. Before F2008, negative unit numbers were never allowed to be used by programs. (Note that non-negative includes zero.) Some implementations (the DEC heritage ones, at least) used negative unit numbers to represent PRINT, READ and WRITE without a unit and internal I/O in a way not directly visible to the user.

NEWUNIT has a special place in my heart, as the very first thing I did after being hired by the VAX FORTRAN group was to design and code a set of run-time library routines that worked a lot like NEWUNIT. They used a pool of nonnegative unit numbers less likely to be used by programs, but still valid. It was a hack, in a way, and I like NEWUNIT much better.

It is not worth arguing. I’d say it would be clearer if it started with *either nonnegative, equal to […], or NEWUNIT value" but it is just my (probably wrong) feeling of English.

I don’t think this is the case. The Standard explicitly requires NEWUNIT to return negative values (actually less than -1). Surely for external files.

The processor could easily keep track of both self- and user-assigned unit numbers, so in principle NEWUNIT could also return nonnegative values but then the user would have to keep track of them in order not to try to assign already-used values in OPEN statements using traditional UNIT= specifier.

I’ve used this function for compilers that didn’t support the new newunit yet:

integer function newunit(unit) result(n)
! Returns lowest i/o unit number not in use (to be used in older compilers).
!
! Starting at 10 to avoid lower numbers which are sometimes reserved.
! Note: largest valid unit number may be system-dependent.
!
! Arguments
! ---------
!
! If present, the new unit will be returned into it
integer, intent(out), optional :: unit
!
! Example
! -------
!
! integer :: u
! open(newunit(u), file="log.txt", status="old")
! read(u, *) a, b
! close(u)
!
! In new compilers, just use the "newunit" keyword argument:
!
! integer :: u
! open(newunit=u, file="log.txt", status="old")
! read(u, *) a, b
! close(u)

logical inuse
integer, parameter :: nmin=10   ! avoid lower numbers which are sometimes reserved
integer, parameter :: nmax=999  ! may be system-dependent
do n = nmin, nmax
    inquire(unit=n, opened=inuse)
    if (.not. inuse) then
        if (present(unit)) unit=n
        return
    end if
end do
call stop_error("newunit ERROR: available unit not found.")
end function
1 Like

So I was wrong about NEWUNIT numbers being positive, so my earlier generalization doesn’t hold together. From section 12.5.6.12 of the 2018 standard

A NEWUNIT value is a negative number, and shall not be equal to −1, any of the named constants ERROR_UNIT, INPUT_UNIT, or OUTPUT_UNIT from the intrinsic module ISO_FORTRAN_ENV (16.10.2), any value used by the processor for the unit argument to a defined input/output procedure, nor any previous NEWUNIT value that identifies a file that is connected. The unit identified by a NEWUNIT value shall not be preconnected.

Sorry for any confusion.