Description
Problem
Currently the Fortran standard requires that all declaration statements are in the declaration section of the program unit, for example:
function foo()
<use-statements>
<declaration-statements>
<executable-statements>
end function foo
and similar for other executable units.
Programs or procedures that are too long to fit on the programmer's screen can be more difficult to read and understand if variable references and their declarations can't be seen on the same page.
Proposal
Don't limit declaration statements to declarative section of the code. However, a variable must not be referenced before it's declared (assuming implicit none
).
The key premise is: Declare variables where you use them. You don't have to, but if you want, you can.
The outcome is improved code readability.
Example
Consider a long program. Normally, you put all declarations at the top:
program a_long_program
integer :: a, b, c
a = 42
... ! many lines of code follow
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
b = 2 * a ! what is b again?
... ! many lines of code follow
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
c = b**2 ! hmm, let me scroll up and see what c is
print *, 'The result is ', c
end program a_long_program
This proposed feature would make the following program valid:
program a_long_program
integer :: a
a = 42
... ! many lines of code follow
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
integer :: b
b = 2 * a
... ! many lines of code follow
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
...
integer :: c
c = b**2
print *, 'The result is ', c
end program a_long_program
Comments
- Block construct could be used to a limited extent to emulate this behavior, however it isn't suitable for this purpose due to other restrictions, especially local scope.
- C, Go, Rust, Nim, Zig, and statically typed Python are examples of popular languages that allow this.
- I think it can be easily implemented in the Standard by simply removing the restriction on where declarations go. I don't know how easy or difficult would this be to implement in compilers.
- This feature does not affect backward compatibility.
Activity
gronki commentedon Nov 12, 2019
Sadly, this would require removing the faulty feature of implicit save (#40), and we already know where this is gonna go.
certik commentedon Nov 12, 2019
This has been requested by some of my colleagues at LANL also. It is common to have a 50 or 100 lines long subroutine with loops which is not really feasible to split it into further subroutines, but it would help to declare variables where they are used, as it would simplify reading the code, if you can see the type of the variable close to where it is used.
cmacmackin commentedon Nov 12, 2019
Agreed, this would be very helpful. If it is too controversial, perhaps we could allow variables to be declared with local scope at the start of block constructs (if/then statements, loops, etc.). Essentially we'd be saying that each of them is implicitly a block construct.
milancurcic commentedon Nov 12, 2019
@gronki Can you explain why? Implicit save would remain regardless of where declaration happens. Maybe I'm missing something.
jacobwilliams commentedon Nov 12, 2019
Being able to declare the variable right where it's given a value is going to make people want to do it all on one line... and then disaster will strike.
certik commentedon Nov 12, 2019
I think there is a way to fix #40 that's backwards compatible (several approaches are suggested there), so if there is enough support for this from the Fortran community, we can make this happen.
milancurcic commentedon Nov 13, 2019
Good! It'll make people learn that pitfall quickly.
I still don't see a technical conflict with implicit save, hopefully @gronki can explain. As far as I can tell they're compatible both in terms of syntax and semantics.
klausler commentedon Nov 13, 2019
I find it hard to characterize this as a good thing, myself.
milancurcic commentedon Nov 13, 2019
@klausler Do you think it's a bad thing, or neutral, and why?
My reasoning for why it's good: Implicit save is an obscure feature. If a novice Fortran programmer is not aware of it, the sooner they encounter it the better, because that will be an opportunity to learn about it and (hopefully) never use it again.
In contrast, as the novice Fortran programmer builds knowledge, experience, and code-base, while still not becoming aware of implicit save, it becomes more likely that this will appear as a bug in code that shipped, whether it's an open source library, or a student class project.
klausler commentedon Nov 13, 2019
The existence of the implicit
SAVE
pitfall is the bad thing.milancurcic commentedon Nov 13, 2019
That I agree with, and has little to do with what I wrote. :)
gronki commentedon Nov 13, 2019
@milancurcic,
they might seem compatible but they are not. Please take note that while in the following code:
you can kind of forgive what was in mind of those designing it: since variable declarations are in what can be considered a "header" of a code block, the value zero is in some way pre-assigned to it before the first execution. Whereas if you declare it mid-code:
it is quite obvious that in the third line you expect that w = 0. Which, in this case, will be true only in the first call. Thus leading to quietly producing incorrect results.
I think static/save variables should remain declared in the beginning of the block only. Otherwise it's making the implicit save problem only deeper and more burning.
And I agree with @cmacmackin that probably allowing declaring variables in more places (beginning of if blocks, within the loops, in the do loop header similarly to forall) would probably resolve most of the problems. As long as you can see the declaration on the same screen as assignment it should be good.
Last but not least, the implicit save feature is so toxic that I would think that committee should consider making an exception from "backwards compatibility" argument here. Like forall, this feature never really caught up, but led to lots of confusion and is misleading. Compiler vendors will probably maintain some compatibility mode for the rare customers that use it.
milancurcic commentedon Nov 14, 2019
This is the argument against implicit save. It holds regardless of where you put the declaration statement.
No -- this is the correct behavior according to implicit save, whether we like it or not.
As I understand it, you're talking about what's intuitive and what we'd expect some code to do. I'm talking about whether they are technically compatible. They still seem very much so!
Yes, I admit there is an issue if a positive feature (declare anywhere) makes a negative feature (implicit save) even more negative. I explained in the earlier message why I think this is a sum-positive.
If I could help in any way, I'd love to see implicit save deprecated and eventually deleted, and declare anywhere enabled, concurrently. But I think two separate issues are conflated here. They should be differentiated.
I don't think an existing negative feature should be a roadblock to implementing other, positive features to the language.
gronki commentedon Nov 14, 2019
36 remaining items