Declare variables anywhere

I don’t think it’s possible, but let’s try: Zen of Fortran

1 Like

I see: “block myblock” should be “end block myblock”.

But j is not an implicit variable - “integer :: j”. I tried a complete version (which had a judiciously placed implict none statement) with gfortran and got the message about j not having a type that I expected.

What am I missing?

Here is the code:

program blockj
    implicit none
    call mysub
contains
subroutine mysub
integer :: i
myblock: block
    integer :: j
    do i = 1,10
        j = i * 2
        if ( j > 5 ) exit myblock
    enddo
    write( *, * ) 'Final value: ', j
end block myblock

! j not defined here?

write(*,*) 'Value of j = ', j
end subroutine mysub
end program blockj

As I understand the block construct, the point is that variables declared within it are only available there; the block is their scope. So you would have to move the end block myblock line below the last use of j. This can get confusing in larger cases, as stated by @milancurcic above.

1 Like

I’d say this is an argument against long program units in the first place :slight_smile:

What I find annoying in Java, C++ or C# code where variables are declared seemingly haphazardly, is that you have to scan the code to find out where these declarations occur. It may be a matter of getting used to and I am sure we will never agree on the Only Correct Way To Program or the One True Style. If we did, programming and discussing programming might become boring.

3 Likes

Well, that ought to teach me to always check my code fragments :slight_smile: , especially when demonstrating diagnostic capabilities.

Declare variables anywhere?

People already do. We found declarations after executable code (without block or associate) in WRF. WRF builds on ifort, gfortran, g95 (or it did), pathscale, fujitsu … So you can already do this with all of those. I see no reason why the standard shouldn’t reflect the behaviour of the compilers. For clarity it might be useful to specify the scope in or before the embedded declarations. That might prevent errors from cut-and-paste editing.

Best wishes, John.

Thanks, John, can you point to any specific source file? I’ve been working with WRF for 12 years and I haven’t seen such declarations.

Hi Milan,

I am away from home, but the latest WRF on the machine I have here gives me:

FPT> t
94 flux5(q_im3,q_im2,q_im1,q_i,q_ip1,q_ip2,ua) = &
95 flux6(q_im3,q_im2,q_im1,q_i,q_ip1,q_ip2,ua) &
96 -SIGN(1,time_step)SIGN(1.,ua)( &
97 (q_ip2-q_im3)-5.(q_ip1-q_im2)+10.(q_i-q_im1))/60.0
98 !
99 !
100 >> LOGICAL :: specified
!--------------^-------------------------------------------------------
!!! FPT - 3493 Declarations follow executable statements
!----------------------------------------------------------------------
101 !
102 specified = .FALSE.
103 IF (config_flags%specified .OR. config_flags%nested)specified = .TRUE.
104 !
105 ! set order for vertical and horzontal flux operators
106 !
FPT> show cursor

The cursor is at line: 100 in file:
wrf_re-eng/UCAR_clean_build/WRFV3/dyn_em/module_advect_em.F
At line: 91 in sub-program: module_advect_em%advect_u

Current scope is “ALL FILES”

FPT>

Now flux5 is a statement function, but that should be after the declarations. There are many like this. I will check current versions of WRF in a few days when I get back to my main machines. This was in 3.4.1 which is ancient.

John

By the way, the reply text box has completely trashed the formatting of the code. fpt is much more respectful!

John

That code is also here.

   specified = .false.
   if(config_flags%specified .or. config_flags%nested) specified = .true.

should be written

specified = config_flags%specified .or. config_flags%nested

and the same verbosity is present elsewhere:

   degrade_xs = .true.
   degrade_xe = .true.
   degrade_ys = .true.
   degrade_ye = .true.

   IF( config_flags%periodic_x   .or. &
       config_flags%symmetric_xs .or. &
       (its > ids+3)                ) degrade_xs = .false.
   IF( config_flags%periodic_x   .or. &
       config_flags%symmetric_xe .or. &
       (ite < ide-2)                ) degrade_xe = .false.
   IF( config_flags%periodic_y   .or. &
       config_flags%symmetric_ys .or. &
       (jts > jds+3)                ) degrade_ys = .false.
   IF( config_flags%periodic_y   .or. &
       config_flags%symmetric_ye .or. &
       (jte < jde-4)                ) degrade_ye = .false.

which should be written

degrade_xs =  config_flags%periodic_x  .or.  config_flags%symmetric_xs .or. &
              its > ids+3

etc. Are there any tools that can simplify such code? Maybe the awkward continuation syntax of Fortran should be preserved so that people are incented to write shorter code :slight_smile: .

If that file is typical, WRF could be written better. Looking at

      i_start = its
      i_end   = ite
      IF ( config_flags%open_xs .or. specified ) i_start = MAX(ids+1,its)
      IF ( config_flags%open_xe .or. specified ) i_end   = MIN(ide-1,ite)
      IF ( config_flags%periodic_x ) i_start = its
      IF ( config_flags%periodic_x ) i_end = ite

it is not easy to see how i_start is set. Clearer is

  IF ( config_flags%periodic_x ) then
     i_start = its
  ELSE IF ( config_flags%open_xs .or. specified ) then
     i_start = MAX(ids+1,its)
  ELSE
     i_start = its
  END IF

or

  IF ( config_flags%periodic_x ) then
     i_start = its
  ELSE
     i_start = merge(MAX(ids+1,its),its,config_flags%open_xs .or. specified)
  END IF

Statement function statements are declaration constructs. Type declaration statements (like LOGICAL :: specified) are too. They can be mixed together. There don’t appear to be any executable statements before the declaration of specified.

1 Like

This is the key. This is very common in Fortran codes that statement functions appear anywhere in declarations. LFortran was tripped by this too and we had to rework our parser.

1 Like

@Jcollins , you will be hard-pressed to find a Fortran processor that allows a specification-part in the execution-part of a program, some relaxation along such lines is what “declare variables anywhere” would require.

None of the processors studied alongside fpt are likely to allow the following:

   print *, "Hello World!"
   integer x
end

Please note the example you give with WRF upthread suggests fpt misconstrues stmt-function-stmt - which is a declaration-construct part of the specification-part - as belonging to an execution-part. That example is not indicative of compilers supporting “declare variables anywhere”.

1 Like

I agree that we should try to rearrange assignments of values to logical variables so as to make the code more readable, but we need to be careful to keep the logic intact.

The above suggested replacement is incorrect; you need to apply .NOT.(…) to the right hand expression.

1 Like

You are quite right. Under extended FORTRAN 77 (e.g. VMS) statement functions were required to lie between the last type/parameter declaration and the first data statement. This is no longer the case, and now data statements can be written anywhere and statement functions can go amongst the type declarations. I have checked the versions of WRF I have with me, and there are no type declarations after executable statements. I will amend fpt to accept statement functions within the declarations (it processes them anyway, just the error message is spurious). Apologies!

4 Likes

Yes, this is spelled out in Table 5.1 in clause 5.3.2 in the standard. There is a lot of apparent weirdness in that table, if I’m reading it correctly. (Like FORMAT statements can appear interspersed with IMPLICIT declarations???)

1 Like

Yes, when you read it carefully as I had to do to figure out what is going on, there is all kinds of freedom that is allowed that I didn’t know about (and don’t want to know about ;).

I wish you could put implicit none just after the program foo or module foo statements and before the use bar statements. I have gotten syntax errors many times for having implicit none in the wrong place.

1 Like

I agree, would prefer to put implicit none right after the program or module.