Will f202x standardize the use of logicals as integers?

I run across the non-standard use of logicals as integers often, and the extensions vary widely between compilers (even vintages of the same compiler family). Any chance f202x will define this behavior? Making it illegal without the use of an extension flag would be fine by me; but with C interops appearing in more and more codes allowing INT() to take a logical seems reasonable.

Recent versions of gfortran are much stricter than in the past and the usage between compilers varies so much I find myself using overloads to “standardize” the usage, which is not ideal (it is not always possible to change others code when I just want to use another compiler for various reasons).

The current state is all over the map. Run this with a few different compilers, for starters:

logicals.F90

program logicals
!! What happens when variables of one type are assigned to another type
implicit none
logical :: y, z
integer :: i, j
y=-0
if(y) error stop '0 should be False'
y=0
if(y) error stop '0 should be False'
y=-1
if(.not.y) error stop '-1 should be True'
print *,'0 and -1 seem to be standardized by convention, nothing else'
do i=-10,10
   z=i
   j=z
   print *, i, z, j
enddo
print *,'even less predictable'
#ifdef __NVCOMPILER
   print *, 'nvfortran: even FALSE odd TRUE, integers round-trip'
   print *, 'z+z=',z+z,'logical or integer?'
   print *, 'int(z):',int(z)
   print *, 'int(z+z)=',int(z+z)
   j=z+z
   print *, 'z+z==j=',j
   print *, z.eq.z,z.gt.y,z.lt.y
#endif
#ifdef  __INTEL_COMPILER
   print *, 'ifort:     even FALSE odd TRUE, integers are 0 or -1'
   print *, 'z+z=',z+z,'logical or integer?'
   j=z+z
   print *, 'z+z==j=',j
   print *, z.eq.z,z.gt.y,z.lt.y
#endif
#ifdef __GFORTRAN__
   print *, 'gfortran:  0 is FALSE, everything else is TRUE'
#endif
end program logicals
gfortran

0 and -1 seem to be standardized by convention, nothing else
-10 T 1
-9 T 1
-8 T 1
-7 T 1
-6 T 1
-5 T 1
-4 T 1
-3 T 1
-2 T 1
-1 T 1
0 F 0
1 T 1
2 T 1
3 T 1
4 T 1
5 T 1
6 T 1
7 T 1
8 T 1
9 T 1
10 T 1
even less predictable
gfortran: 0 is FALSE, everything else is TRUE

ifort

0 and -1 seem to be standardized by convention, nothing else
-10 F 0
-9 T -1
-8 F 0
-7 T -1
-6 F 0
-5 T -1
-4 F 0
-3 T -1
-2 F 0
-1 T -1
0 F 0
1 T -1
2 F 0
3 T -1
4 F 0
5 T -1
6 F 0
7 T -1
8 F 0
9 T -1
10 F 0
even less predictable
ifort: even FALSE odd TRUE, integers are 0 or -1
z+z= F logical or integer?
z+z==j= 0
T T F

nvfortran

0 and -1 seem to be standardized by convention, nothing else
-10 F -10
-9 T -9
-8 F -8
-7 T -7
-6 F -6
-5 T -5
-4 F -4
-3 T -3
-2 F -2
-1 T -1
0 F 0
1 T 1
2 F 2
3 T 3
4 F 4
5 T 5
6 F 6
7 T 7
8 F 8
9 T 9
10 F 10
even less predictable
nvfortran: even FALSE odd TRUE, integers round-trip
z+z= 20 logical or integer?
int(z): 10
int(z+z)= 20
z+z==j= 20
T T F

1 Like

gfortran 10.3 was actually the strictest of the three shown and no longer(I think it used to) allowed some of the worst extensions; which I think is preferable; but if everyone is allowing extensions and they vary I think that is actually a worse case than standardizing it. Standardizing it would at least remove the variability, which can add subtle bugs as the results of the little test hints at. I would be totally fine with it all being strictly illegal without specifically asking for the extension too. I wasted some serious time because of the one compiler only treating 0 as false and another treating even values as false and odd as true; and because C doesn’t have an exact match for logicals I think it will cause more portability issues in the future to not standardize the behavior. I agree in spirit with your statements but it seems (probably because the compilers allowed it) this type of usage is quite common.

I think it comes down to how the committee feels about breaking backwards compatibility of vendor extensions. Since different compilers did it differently, if it gets standardized, those who did it different from the way that got standardized will be in a pickle. Do they continue to use their existing, non-standard behavior as the default, or change their default behavior, potentially breaking some of their existing users code?

If this behavior did get standardized, I would be in favor of mimicking typical usage in C and other languages; 0 is false, everything else is true.

Not a chance. I haven’t even heard this floated as an idea in the committee before.

This extension (free conversion between logical and numeric) became popular with VAX FORTRAN because of the way that VMS status codes were designed, such that values with the low bit set were success or informational, and those with low bit clear were warning, error or fatal. VAX FORTRAN then defined a true/false test on integers to be a low bit test (VAX had branch-on-low-bit clear/set instructions) so you could just do a true/false test on a status to see if it succeeded or failed.

That was bad enough, but DEC went farther and allowed free conversions for real/complex and also in list-directed and NAMELIST input. I did, eventually, convince the team (might have been in the early Intel days, possibly before) to turn off the list-directed/NAMELIST feature (you could enable it with an option.)

Many people want to use logical operators such as .AND. and .OR. on integers to do bitwise stuff, even though the language has perfectly good support for doing that properly (IAND, IOR). Many don’t realize that you can use IANY and IALL to “reduce” multiple integer values using AND or OR.

I wrote more about this at Doctor Fortran in “To .EQV. or to .NEQV., that is the question”, or “It’s only LOGICAL” - Doctor Fortran (stevelionel.com)

4 Likes

The original definition allowed for a true single-bit representation regardless of endian when memory was precious enough that saving a word of storage was something important, but nowadays all three of the tested compilers return 32 for STORAGE_SIZE(.true.). Some of them, as the test shows, already allow almost all uses of a logical as a default integer type, and some people actually use the resulting “features”, creating, often accidently, unportable code.

Very nice description in the article of some of the issues. One of the complaints I hear about Fortran is it cannot be used for bit-level manipulation (but as the above describes it certainly can be misused) but I think that is more from not having an unsigned integer (it certainly does have procedures)

bit-level procedures
atomic_and       - [ATOMIC:BIT MANIPULATION] Atomic bitwise AND operation
atomic_fetch_and - [ATOMIC:BIT MANIPULATION] Atomic bitwise AND operation with prior fetch
atomic_fetch_or  - [ATOMIC:BIT MANIPULATION] Atomic bitwise OR operation with prior fetch
atomic_fetch_xor - [ATOMIC:BIT MANIPULATION] Atomic bitwise XOR operation with prior fetch
atomic_or        - [ATOMIC:BIT MANIPULATION] Atomic bitwise OR operation
atomic_xor       - [ATOMIC:BIT MANIPULATION] Atomic bitwise OR operation
bge              - [BIT COMPARE] Bitwise greater than or equal to
bgt              - [BIT COMPARE] Bitwise greater than
ble              - [BIT COMPARE] Bitwise less than or equal to
blt              - [BIT COMPARE] Bitwise less than
bit_size         - [BIT INQUIRY] Bit size inquiry function
leadz            - [BIT INQUIRY] Number of leading zero bits of an integer
popcnt           - [BIT INQUIRY] Number of bits set
poppar           - [BIT INQUIRY] Parity of the number of bits set
storage_size     - [BIT INQUIRY] Storage size in bits
trailz           - [BIT INQUIRY] Number of trailing zero bits of an integer
btest            - [BIT MANIPULATION] Bit test function
dshiftl          - [BIT MANIPULATION] combines bits of arguments I and J
dshiftr          - [BIT MANIPULATION] combines bits of arguments I and J
iall             - [BIT MANIPULATION] Bitwise and of array elements
iand             - [BIT MANIPULATION] Bitwise logical and
iany             - [BIT MANIPULATION] Bitwise or of array elements
ibclr            - [BIT MANIPULATION] Clear bit
ibits            - [BIT MANIPULATION] Bit extraction
ibset            - [BIT MANIPULATION] Set bit
ieor             - [BIT MANIPULATION] Bitwise logical exclusive or
ior              - [BIT MANIPULATION] Bitwise logical inclusive or
iparity          - [BIT MANIPULATION] Bitwise exclusive or of array elements
ishft            - [BIT MANIPULATION] Shift bits
ishftc           - [BIT MANIPULATION] Shift bits circularly
logical          - [BIT MANIPULATION] Converts one kind of LOGICAL variable to another
merge_bits       - [BIT MANIPULATION] Merge of bits under mask
mvbits           - [BIT MANIPULATION] Move bits from one integer to another
not              - [BIT MANIPULATION] Logical negation
shifta           - [BIT MANIPULATION] shift bits right with fill
shiftl           - [BIT MANIPULATION] shift bits left
shiftr           - [BIT MANIPULATION] shift bits right
transfer         - [BIT MANIPULATION] Transfer bit patterns

It is often noted that an advantage of Fortran over C/C++ is that it is harder to make mistakes and they are often caught at compile time but this particular topic belies that, IMO. I was hoping it could be cleaned up, at least by compilers treating it as an error by default.

I do wish, with regards to switches like --std= there was some convention like --std=latest that would enforce the latest standard behavior supported by the compilers everyone agreed to, or requiring a file containing non-standard usage to end in .f- or .f90-.

1 Like

I agree with @sblionel and @kargl, using integers instead of Booleans is an anti-feature.

To me, something like

integer :: return_value

return_value = 1
if (return_value) print*, 'error'

looks strange, especially since Fortran is a strongly typed language.

What is wrong with if (return_value /= 0) print*, 'error'? The four extra letters improve readability a lot if return_value can have more than two values and if not, one can use a Boolean.

Many programmers will understand the convention that 0 equals false, but IMHO not because it is logical but simply because it is a common expression in many languages. In Python even an empty dictionary evaluates to false in an if statement. I find this simply confusing.

1 Like