Whether to eliminate implicit mapping has been much discussed here, and the argument against doing so is that removing it would break a lot of working, standard-conforming code.
Would it be feasible to eliminate the use of variables in a print or write statement or the RHS of an assignment that have never been declared and have not been set? The code
euler = 0.577215
print*,euler
end
would still be allowed
but
euler = 0.577215
print*,eulr ! note typo
end
would not be. It would still be allowed to use an undeclared and unset variable in a subroutine call or function reference, because the subroutine may set the variable or never use it, and the function may never use it.
Currently the 2nd code can be compiled with gfortran -std=f2018 and gives random output. I don’t think this should persist indefinitely for future standards.
The standard already disallows undefined variables from appearing in uses where their value is required. But this is not something that can be reliably checked at compile-time, so it isn’t a constraint. Some compilers can diagnose this, and a few do it by default.
The idea makes sense for scalar variables of intrinsic type, but consider what might happen if euler is an array, say euler(4), and only its elements with indices 1 and 3 are defined, the array is in the output list of a diagnostic PRINT statement, and whether elements are defined or not is not knowable at compile time.
Similar problems may arise when (a) a copy of a variable of any type is made into a temporary variable, to be used only after an error condition might occur later, or (b) partial definition of a user-defined type variable, i.e., only some elements are defined and the undefined elements are used only in diagnostic print statements.
My objections could be deflected if Fortran were to provide an intrinsic inquiry function defined() or initialized() similar to present(), associated(), allocated(), etc…
My proposal is intended to catch spelling errors in variable names when the user fails to use implicit none. The compiler cannot be expected to catch the use of all uninitialized variables at compile time. Already you cannot refer to euler(4) unless you previously had either real euler(4) or dimension euler (4) earlier in the program unit.
The general term is use before define. This falls into the “quality of implementation” category. A compiler should be able to detect this in some cases (and I believe some compilers do), but probably not in the general case. For local and intent(out) variables it’s usually pretty obvious. You don’t even need the lack of a declaration to be able to detect that in most cases. But, in the case of use or host associated variables, intent(inout) or no intent arguments, or it’s passed as an argument to a procedure that might have defined it first, all bets are off. All that being the case, it certainly can’t be made a constraint, so compilers aren’t strictly required to detect the error at compile time, and the already present prohibition on use before define in the standard covers it.
My recollection is that the “define before use” problem in general is not computable; the Halting Problem can be reduced to it. It falls into the general category that “any non-trivial property of a program is undecidable”.
Most compilers that detect the error look to see if there are any possible paths to a “use” that don’t appear to have a “define” along the way. They look at all the branches of conditional constructs and expect to see some kind of definition…
integer :: i
real :: h
call random_number(h)
if (h > 0.5) then
i = 1
else if (h > 0.3) then
i = 0
! else
! 'i' not set in this potential path
endif
print *, i ! Maybe notice that 'i' wasn't set on every potential path
end