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.
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.