New syntax to disallow narrowing conversion as in C++

C++ now has a syntax to disallow a narrowing conversion. Compiling

#include <iostream>

int main()
{
	const int i = {2.1}; // invalid
	const int j = 2.1;   // legal
	std::cout << "i =" << i;
}

with g++ gives

narrow.cpp: In function 'int main()':
narrow.cpp:5:24: error: narrowing conversion of '2.1000000000000001e+0' from 'double' to 'int' [-Wnarrowing]
    5 |         const int i = {2.1};
      |

Narrowing conversions, both in setting named constants and variables, cannot be removed from Fortran, but could a new syntax be created where they are prohibited? Since curly brackets signify modernity :slight_smile: , could Fortran allow them on the RHS, so that

integer, parameter :: i = {2.1}
real(kind=kind(1.0d0)), parameter :: pi = {3.14159265359}

is illegal

while

integer, parameter :: i = 2.1
real(kind=kind(1.0d0)), parameter :: pi = 3.14159265359

remains legal?

Gfortran does give warnings such as

    3 | integer, parameter :: i = 2.1
      |                         1
Warning: Change of value in conversion from 'REAL(4)' to 'INTEGER(4)' at (1) [-Wconversion]

but I think a way of disallowing narrowing conversions should be part of the standard.
The syntax would be available for both variables and named constants, but people might use it only for named constants to avoid cluttering all assignments.

1 Like

I think this post might benefit from being merged with the with the F202Y discussion
See:
Kickstarting proposals for F202Y features

I kind of like the sentiment, but not really the syntax. Perhaps a new assignment operator that does not have interfaces defined for assignment from high-precision to lower precision variables? Like

real(kind=kind(0.0d0)), parameter :: pi =@ 3.14159 ! invalid
real(kind=kind(0.0d0)), parameter :: pi =@ 3.14159d0 ! valid

real :: x

x =@ 2 + 3 ! invalid
x =@ real(2+3) ! valid

I lean towards it not really being necessary, or at least high priority, since in practice most compilers can already give warnings about such things and allow turning warnings into errors. For existing code you’d have to do that anyways to go find current misuse, and you’d have to convince people to start using the new syntax everywhere.

1 Like

Typically these two won’t be the so-called narrowing conversions.

2 Likes

Yep, totally got those backwards. Maybe it shouldn’t just be narrowing conversions, but any conversions?

To be clear, I was going off the cuff and not being careful enough/thinking clearly about my example. The proper example would have been more like

real, parameter :: pi =@ 3.14159d0 ! invalid
real(kind=kind(0.0d0)), parameter :: pi =@ 3.14159d0 ! valid

integer :: i

i =@ 2.0 + 3 ! invalid
i =@ int(2.0+3) ! valid

But x =@ 2 + 3 is also potentially a mistake. Did you really mean to assign an integer value to a real variable?

But like I said, I think this should be a pretty low priority.

If anything, I think this should be an optional tool (compiler, IDE) feature, not a language feature. Sometimes other languages show us what not to do.

2 Likes

In the case of REAL intrinsic type with instructions particularly where literal constants come into play (e.g., in the definition of named constants), allowing narrowing conversions has long been a feature, not a bug: the standard has, “The significand may be written with more digits than a processor will use to approximate the value of the constant.”

There are codes that explicitly take advantage of this e.g., with the case indicates upthread with PI where the base named constant gets defined with more digits than the processor will use even toward the highest precision it supports and subsequently, narrowing conversions are performed for named constants of lower precision.