j3-fortran / fortran_proposals

Proposals for the Fortran Standard Committee
178 stars 15 forks source link

Mods to support refactoring legacy codes to remove GO TO #68

Open rweed opened 5 years ago

rweed commented 5 years ago

Over the last few months, I've gone through the process of "depastafying" some old codes with the goal to remove all instances of GO TO. I did this because in many cases deconstructing the code was the only way I could figure what it was doing. In a large percentage of cases, the GO TOs are used in cases where we would today use IF-THEN-ELSE-ENDIF blocks and the modifications are straightforward. In other cases where you have interlacing branch-backwards, branch-forward GO TOs that iterate through blocks of code, I've found that combinations of unindexed DO, the BLOCK construct and internal subroutines are needed. Finally, the third most frequent use of GO TOs is to jump out of an iteration directly to output statements that print error or other information prior to exiting or stopping. Based on this experience, I've come up with a few modifications that I think would be helpful for those as foolish as me that feel the need to exteriminate GO TO in all its forms.

First, I would like to propose a new construct I call an ITERATION that combines the functionality of BLOCK and unindexed DOs into a single construct. Currently, you can exit BLOCK but not CYCLE it. Unindexed DO allows both. Just about every Fortran code ever written will have the following code fragment; Integer :: reccount = 0

10 Read(7, ('(A)'). ERR=20, END=30) buf ! Translate buf to something reccount = reccount + 1 GO TO 10 20 Print something RETURN 30 Print EOF message

 My mod would replace this with
READLOOP: ITERATION
 Integer :: ioval
 Integer :: reccount = 0
 Character(LEN=80) :: buffer
 Read(7, '(A)', IOSTAT=ioval) buffer
 If (ioval /= 0) EXIT READLOOP

End ITERATION READLOOP

This is a simple example but the utility of it really becomes clear when you have to use a BLOCK statement around a large block of code just to handle exiting out of the enclosed BLOCK to some error handling code (usually selected by a SELECT CASE parameter set prior to exiting the BLOCK). I know that this replicates current capabilities by I've always felt that unindexed DO was a poor syntax choice (one of many syntax "crimes" I believe were made by prior committes and have to date gone unpunished)

In addition, I would like to implement an EXIT_TO clause in all the named constructs (DO, BLOCK, etc) that allows you to jump directly to another named construct. The constraint is unlike GO TO it can only jump to the beginning of a block of code contained in another named construct

Example

Do i=1,n If (error_detected) EXIT_TO error_output End Do ! lots of lines of code inbetween error_output: Block ! process error code etc End Block error_output

Finally, if we still have a need for statement labels, at least let them be fully alphanumeric instead of just numbers. This would make them a lot more readable. In particular, I would like to be able to assign a meaningful label to FORMAT statements that reflect what they are doing.

Example

Write (7,threeReals) a, b, c

threeReals: Format(3(f10.5))

I know you can do the same using character strings but for the target application( refactoring old code) I think this would be a useful feature.

I can supply examples of real code where I've use both BLOCK and unindexed DO to remove GO TO if that would help

Another reason for proposing these is a hope that some enterprising young person in search of a Masters or Ph.D. thesis topic will develop some open source refactoring tools based on AI/Deep Learning that can remove Go Tos automatically. Maybe a Google Summer of Code project. These constructs would give the refactoring tools something to convert the old code into.

Just some ideas based on recent experience

FortranFan commented 5 years ago

@rweed, your statement, "combinations of unindexed DO, the BLOCK construct and internal subroutines" hits the nail on the head in that a combination of these form the "canonical" construct in terms of "structured programming" implied by current standard.

Considering there are more than enough nuances that need to be handled in each code-base usually and particularly in scientific and technical computing that has to deal to considerable domain-specific complexity, an imperative language such as Fortran might be better off offering general constructs that can be used by coders broadly e.g., general DO which can be used for IO, numeric iterations and also any other instructions requiring a loop.

Your second example involving a jump to another construct in terms of "EXIT_TO error_output" appears more of a case of structured exception handling and it is perhaps better addressed in this issue #66 . Besides the exception handling use case, an EXIT_TO appears no different than a GO TO and given your title and description, it appears something which is better avoided, Also, it is unclear how any limited "GO TO" in the form of an EXIT_TO construct can make refactoring any more accurate or easier, if you can show an actual refactoring tool (Python script. etc.) that might help make your case.

Now, re: your case, as you know you will get steered toward named constants or CHARACTER variables generally as FORMAT strings:

   ..
   character(len=*), parameter :: UnlimitedReals = "(*(f10.5))"
   ..
   Write (7, UnlimitedReals) a, b, c

So my hunch is a major "selling" effort on your part will be necessary to get committee's attention on such aspects.

Liebenfiels commented 1 year ago

Without GOTO it is not Fortran anymore, Fortran has a GOTO the same as BASIC if you look to 80-90s books, manuals and software. If you aim to do fundamental changes then fork the language and call it something else than Fortran

FortranFan commented 1 year ago

Without GOTO it is not Fortran anymore

This is merely an opinion to which some might agree, but some may not and most may yawn.

Anyways, now there is absolutely no technical need for GO TO in Fortran codes given other options that yield better structured programming styles.

Regardless, GO TO remains a feature in the language and any practitioner can use it as they choose. Even the Computed GO TO remains only marked as obsolescent, meaning it remains a first-class feature until (if at all ever) it gets deleted.

ivan-pi commented 1 week ago

As long as goto is kept, I think a minor improvement, would be to allow jumping to a labelled block, and not only a numeric label. This would also apply to read(err=<label>, ...) and similar statements.

Just to be more concrete,

if (error) goto 20
! ...

return
20 continue
! ... error handling

could become,

! ...
if (error) goto err
return

err: block
   ! ... error handling
end block err

In essence I'm proposing to allow what C has.

Liebenfiels commented 6 days ago

In Linux in C they use GOTO to leave deep nested loop, something Python does not have. The problem I seen at time is, lot of early Fortran code has GOTO like Basic and VB kept it for that reason.

The worst is to have backward compatibility problem like Python 2 to Python 3. They changed too many things, what saves them not many used Python 2 at time. GO lang and that is new language circa 2008 has GOTO.