I agree the current state of affairs would be difficult to improve upon without breaking backward compatibility, but I was thinking how long this has been a point of confusion. To help explain it in the past I used to use an example somewhat like the following, especially to highlight how E and D suffixes do not impact NAMELIST and most input, but are effective on output, and to warn about truncation of long constants without an explicit type. It went something like this, except I know “g0” was not available:
program pidigits
character(len=80) :: cpi='3.141592653589793238462643383279502884197169399375105820974944592307'
character(len=80) :: cpi1='3.141592653589793238462643383279502884197169399375105820974944592307e0'
character(len=80) :: cpi2='3.141592653589793238462643383279502884197169399375105820974944592307d0'
doubleprecision :: pi,pi1,pi2,pi3,pi4,pi5
namelist /args/ pi
character(len=256) :: input(3)=[character(len=256) :: &
&'&args', &
& ' pi=3.141592653589793238462643383279502884197169399375105820974944592307,', &
& '/']
data pi2/3.141592653589793238462643383279502884197169399375105820974944592307e0/
data pi3/3.141592653589793238462643383279502884197169399375105820974944592307d0/
pi4=3.141592653589793238462643383279502884197169399375105820974944592307e0
pi5=3.141592653589793238462643383279502884197169399375105820974944592307d0
write(*,'(g0)')cpi
write(*,'(g0)')pi2,pi3,pi4,pi5
read(input,nml=args)
write(*,'(g0)')pi
read(cpi,*)pi1
write(*,'(g0)')pi1
read(cpi1,*)pi1
write(*,'(g0)')pi1
read(cpi2,*)pi1
write(*,'(g0)')pi1
write(*,'(g0)') 3.141592653589793238462643383279502884197169399375105820974944592307
write(*,'(g0)') 3.141592653589793238462643383279502884197169399375105820974944592307e0
write(*,'(g0)') 3.141592653589793238462643383279502884197169399375105820974944592307d0
end program pidigits
and how the value of a constant may change with compiler options such as
ifort pi.f90 -r8
nvfortran pi.f90 -r8
gfortran -fdefault-real-8 pi.f90 -fdefault-double-8
was always an issue too.
A common comment was that most thought that a constant should be promoted to a type large enough for all the explicitly given digits or a warning be required to be given.
I think all modern compilers have a switch that will produce a warning about constants being truncated and about precision possibly being lost when the LHS and RHS types do not match,
which people should be encouraged to use, especially as more users now use languages with features such as arbitrary precision that therefore might be even more surprised than in the past about values they explicitly entered being significantly truncated.
Even if automatic promotion to a kind sufficient to hold the explicit values was the rule, people would probably still be surprised that “A=1.0” might not produce the same as “A=1.00000000000”, so I am not certain that change would be better, and there is still the issue that compilers can have different default types; but I do think the most inadvertent error is caused by “double_value = single_precision_constant”, which that would not address anyway.
Maybe a new syntax like “value <== constant” where the constant would be treated the same as if it were read with list-directed input would address constants, but that would not address where the constants are used in functions.
And it looks like the rule about LHS being ignored when determining the value on the RHS
is too sacrosanct to be broken, which seems like the only logical path to improving the current state. SIgh. I really have had a number of complaints about this though. It is very non-intuitive .
So overall, it looks like the status-quo is a reasonable compromise, but quite a mess.