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 , 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.
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.
Why would x =@ 2 + 3 be invalid? Both 2 and 3 and their sum are exactly representable in all floating point formats supported by all of today’s Fortran processor. There is no loss of precision in the conversion and assignment. So, are you going to restrict the invalidness to say x =@ 2**digits(x) + 1.
If it is my code, “yes”. If the integer-literal-constant is exactly representable as a particular real, then I would write x = 2 + 3 rather than x = 2._knd + 3._knd. To me, the former is cleaner.
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.
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.