Skip to content

Allow declaration statements anywhere #81

Open
@milancurcic

Description

@milancurcic

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

gronki commented on Nov 12, 2019

@gronki

Sadly, this would require removing the faulty feature of implicit save (#40), and we already know where this is gonna go.

certik

certik commented on Nov 12, 2019

@certik
Member

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

cmacmackin commented on Nov 12, 2019

@cmacmackin

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

milancurcic commented on Nov 12, 2019

@milancurcic
MemberAuthor

Sadly, this would require removing the faulty feature of implicit save (#40), and we already know where this is gonna go.

@gronki Can you explain why? Implicit save would remain regardless of where declaration happens. Maybe I'm missing something.

jacobwilliams

jacobwilliams commented on Nov 12, 2019

@jacobwilliams

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

certik commented on Nov 12, 2019

@certik
Member

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

milancurcic commented on Nov 13, 2019

@milancurcic
MemberAuthor

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.

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

klausler commented on Nov 13, 2019

@klausler

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.

Good! It'll make people learn that pitfall quickly.

I find it hard to characterize this as a good thing, myself.

milancurcic

milancurcic commented on Nov 13, 2019

@milancurcic
MemberAuthor

@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

klausler commented on Nov 13, 2019

@klausler

The existence of the implicit SAVE pitfall is the bad thing.

milancurcic

milancurcic commented on Nov 13, 2019

@milancurcic
MemberAuthor

That I agree with, and has little to do with what I wrote. :)

gronki

gronki commented on Nov 13, 2019

@gronki

@milancurcic,

they might seem compatible but they are not. Please take note that while in the following code:

subroutine do_xyz
integer :: counter = 0
integer :: i
read (*, *) i
counter = counter + i

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:

x = y + z
real :: w = 0
w = w + x

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

milancurcic commented on Nov 14, 2019

@milancurcic
MemberAuthor

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.

This is the argument against implicit save. It holds regardless of where you put the declaration statement.

Thus leading to quietly producing incorrect results.

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

gronki commented on Nov 14, 2019

@gronki

36 remaining items

Loading
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Clause 8Standard Clause 8: Attribute declarations and specifications

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

      Development

      No branches or pull requests

        Participants

        @certik@milancurcic@jacobwilliams@kbauer@cmacmackin

        Issue actions

          Allow declaration statements anywhere · Issue #81 · j3-fortran/fortran_proposals