Flow-control structures: Difference between revisions

→‎{{header|Fortran}}: In case there's any doubt, yes, I have perpetrated every above scheme in one way or another... Peccavi.
(→‎{{header|Fortran}}: In case there's any doubt, yes, I have perpetrated every above scheme in one way or another... Peccavi.)
Line 525:
 
=={{header|Fortran}}==
===The basic: GO TO ''label''===
Fortran offers <code>GO TO ''label''</code> where ''label'' is a number, an integer, which is prefixed to some executable statement according to the rules of Fortran source layout. Fortran has no reserved words and gives no significance to spaces, so that <code>G O TO 12 3 4</code> is just as valid as <code>GO TO 1234</code> and other usages. As a result of this, text labels are difficult to fit into the syntax so that the likes of <code>GO TO START</code> are unavailable. However, a compiler may offer the "assigned GO TO" facility, with statements such as <code>ASSIGN 120 TO THENCE</code> scattered about: 120 is a statement label, not an integer, and any statement label may be assigned to variable THENCE (which is an integer variable) as execution proceeds. Then <code>GO TO THENCE</code> will cause a GO TO for the current address held in THENCE... Should you yield to temptations such as <code>THENCE = THENCE - 6</code> (treating it as an ordinary integer), a subsequent <code>GO TO THENCE</code> may end execution with an error message, or something else...
Fortran offers <code>GO TO ''label''</code> where ''label'' is a number, an integer, which is prefixed to some executable statement according to the rules of Fortran source layout. It is not considered to be a numerical value, though zero is not an allowed label. Fortran has no reserved words and gives no significance to spaces, so that <code>G O TO 12 3 4</code> is just as valid as <code>GO TO 1234</code> and other usages. As a result of this, text labels are difficult to fit into the syntax so that the likes of <code>GO TO START</code> are (normally) unavailable.
 
===Elaborations on GO TO===
This sort of behaviour actually can be put to a positive use to handle the situation where in a large programme there may be portions that could be employed from a number of locations, and one does not wish to repeat that code each time.<lang Fortran> ...
Fortran offers <code>GO TO ''label''</code> where ''label'' is a number, an integer, which is prefixed to some executable statement according to the rules of Fortran source layout. Fortran has no reserved words and gives no significance to spaces, so that <code>G O TO 12 3 4</code> is just as valid as <code>GO TO 1234</code> and other usages. As a result of this, text labels are difficult to fit into the syntax so that the likes of <code>GO TO START</code> are unavailable. However, aA compiler may offer the "assigned GO TO" facility, with statements such as <code>ASSIGN 120 TO THENCE</code> scattered about: 120 is a statement label, not an integer, and any statement label may be assigned to variable THENCE (which is an integer variable) as execution proceeds. Then <code>GO TO THENCE</code> will cause a GO TO for the current address held in THENCE... Should you yield to temptations such as <code>THENCE = THENCE - 6</code> (treating it as an ordinary integer), a subsequent <code>GO TO THENCE</code> may end execution with an error message, or something else...
 
This sort of behaviour actually can be put to a positive use to handle the situation where in a large programme there may be portions that could be employed from a number of locations, and one does not wish to repeat that code each time - apart from the tedium of punching additional cards, each replication would demand its own unique set of statement labels. Further, such replication increases the total code size and memory is limited... <lang Fortran> ...
ASSIGN 1101 to WHENCE !Remember my return point.
GO TO 1000 !Dive into a "subroutine"
Line 541 ⟶ 545:
Since Algol in the 1960s it has been possible to define a routine within a larger routine that has access to all the context of the larger routine and so can be a convenient service routine for it, but Fortran does not allow a subroutine (or function) to be defined within a larger subroutine, except for the arithmetic statement function. One must write separate subroutines and struggle over providing access to context via COMMON and parameters. However, F90 allows a subroutine (or function) to use the CONTAINS feature, after which such a contained routine may be placed. Alas, it may not itself invoke CONTAINS even though Algol allows nesting as desired. And oddly, the contained must be at the ''end'' of the containing routine. So much for definition before usage.
 
Once started on this path, many opportunities beckon: perhaps not just action "A" (achieved by "subroutine" 1000) is of use, there may be an action "B", and so on. One can then prepare the equivalent of a "to-do" list via something like<lang Fortran> ASSIGN 2000 TO WHENCE !Deviant "return" from 1000 to invoke 2000.
Another such usage would be to implement "coroutines", the classic example being to imagine a system that processes both Fortran statements and Fortran commentary, but each in their own way. After scanning some Fortran source, commentary is found so control flows to resume the commentary processing from where it had left off, then when further Fortran source is found, control flows back whence the Fortran source process left off. This is quite different from having subroutines FCODE and FCOMM which when invoked start at their start each time rather than picking up where they left off.
ASSIGN 1103 TO THENCE !Desired return from 2000.
GO TO 1000
1103 CONTINUE</lang>
So that subroutine" 1000 would be invoked, which then invokes subroutine 2000, which returns via THENCE. Those familiar with LISP and similar languages will recognise a struggle to create new "verbs" from existing verbs, and their resulting usage in compound expressions.
 
Another such usage would be to implement "coroutines", the classic example being to imagine a system that processes both Fortran statements and Fortran commentary, but each in their own way. After scanning some Fortran source, commentary is found so control flows to resume the commentary processing from where it had left off, then when further Fortran source is found, control flows back whence the Fortran source process left off. This is quite different from having subroutines FCODE and FCOMM which when invoked start at their start each time (as say when a new statement begins) rather than picking up where they left off because the switches occurred in the middle of a statement. Quite aside from questions of mutual recursion.
There is also a "computed GO TO" with syntax like <code>GO TO (101,50,75,50), ''n''</code> where ''n'' is an integer variable (or expression) that selects from the list of statement labels: in this example if its value is three, then the third label, 75, will be selected. If the value is less than one or greater than the number of labels in the list, odd behaviour is likely, differing by compiler. Possibly by continuing with the next statement, or ending execution with an error message, or making a leap into the void.
 
====If one is good, more are better?====
There is also a "computed GO TO" with syntax like <code>GO TO (101,50,75,50), ''n''</code> where ''n'' is an integer variable (or expression) that selects from the list of statement labels: in this example if its value is three, then the third label, 75, will be selected. If the value is less than one or greater than the number of labels in the list, odd behaviour is likely, differing by compiler. Possibly by continuing with the next statement, or ending execution with an error message, or making a leap into the void. This statement can be used to produce a tangle as described for the ASSIGN facility, but is commonly used as a central direction station, or "dispatch table" for instance when a programme accepts an input which is one of a number of commands and after identifying it from a list of recognised commands (such as "List", "Dump", LineFit", "Quit", ''etc.''), performs a computed GO TO to reach the portion that processes that command. Again, familiar to LISP programmers.
 
===Escape from mishap===
An implicit GO TO can appear in READ and WRITE statements (and a few others), that will be taken should there be certain difficulties. Thus <code>READ (IN,6,END = 200, ERR = 300) STUFF</code> reads input from I/O unit IN (an integer value) into variable STUFF according to the FORMAT statement labelled 6. But should there be instead an end-of-file, rather than ending execution with an error code, execution will GO TO label 200, while if there should arise some difficulty with the format of the incoming data (two decimal points in one data field, ''etc.'') then execution will GO TO label 300. FORMAT statements, though labelled, are not considered suitable destinations for GO TO jumps.
 
===Deviant RETURN===
Similar possibilities arise with alternate returns from subroutines and functions, for instance to handle error conditions it might wish to report as with the READ statement. Thus, <code>CALL FRED(THIS,*123,*THENCE)</code> invokes a subroutine FRED with three parameters: THIS, then two oddities. The leading * (or &) signifies that these are no ordinary integers (or expressions) but instead are the labels of statements somewhere within the calling routine. Subroutine FRED might return in the normal way so that execution continues with the following statement, or, it may instead return with a GO TO for one of the labels...<lang Fortran> SUBROUTINE FRED(X,*,*) !With placeholders for unusual parameters.
...
Line 555 ⟶ 568:
More delicate souls prefer to see an integer parameter whose value will be set by FRED according to the desired condition, and every call to FRED would be followed by a computed GO TO on that value. Except that this statement is also disapproved of, so one is encouraged to code IF, or CASE, ''etc.'' and enjoy the repetition.
 
Thus, a subroutine (or a function) may exit via a RETURN statement, rather than by completing its logic and "falling out" of the end of its definition. If the subprogram is large, these escape holes may be missed by the (human) reader! Similarly, within a DO-loop, a GO TO might jump out of the loop(s), but more interesting is the possibility of jumping into a DO-loop's scope, possibly after jumping out - who knows what its index variable might have been changed to. This is considered poor form by others not writing such code and some compilers will reject any attempts. With the F77 introduction of IF ... THEN ... ELSE ... END IF constructions, jumping out of a block is still acceptable but jumping in is frowned on (even if only from the THEN clause to some part of its ELSE clause) and may be prevented.
 
Persons writing in assembler have further opportunities, for example providing an integer function such as IOR(A,B) that performs an '''or''' on integers A and B. Instead of doing so, the function overwrites its invocation by placing in-line code that performs A '''or''' B, then returns not to its return address but to where it was invoked from so as to compute the result.
More potent than RETURN is STOP, which ends the flow of execution there and then. Early Fortran also allowed STOP ''n'' where ''n'' was a number such as 303 and this value might be displayed on the computer's console display register in bright lights, or be printed in the job log, or on the standard output device. A later extension was STOP "message", but alas the message is only a fixed text, one can't devise a custom report such as "307 values! limit is 300"
 
====Away, and maybe, back====
Instead of STOP, there is PAUSE with the same syntax. The flow of execution would pause (that is, the entire computer would come to a stop in the days when one job only would run at a time), to be resumed with the next statement on the pressing of a button on the computer console for instance after the message "Attach output tape", or, ... the operator could via controls on the console cause execution to resume at some other (any other) chosen address...
Similarly to escaping from a subroutine, within a DO-loop, a GO TO might jump out of the loop(s) - perhaps for good reason. More interesting is the possibility of jumping ''into'' a DO-loop's scope, possibly after jumping out - who knows what its index variable might have been changed to. This is considered poor form by others not writing such code and some compilers will reject any attempts. With the F77 introduction of IF ... THEN ... ELSE ... END IF constructions, jumping out of a block is still acceptable but jumping in is frowned on (even if only from the THEN clause to some part of its ELSE clause) and may be prevented.
 
F90 offers a more decorous means for exiting DO-loops, including the additional DO WHILE loop, via the statements CYCLE and EXIT - the text "GO TO" does not appear as such, but the effect is the same. The CYCLE option means abandoning further statements within the block to test afresh the iteration condition, while EXIT means ending the iteration as if it had completed. Further syntax allows some compiler checking, as follows: <lang Fortran>
Line 573 ⟶ 587:
A DO-loop can be given a label such as XX (which is ''not'' in the numeric-only label area of fixed source format Fortran, and the syntax highlghter has missed yet another trick of Fortran syntax) and its corresponding END DO can be given a label also: the compiler checks that they match and some programmer errors might thereby be caught. With such labels in use, the CYCLE and EXIT statements can name the loop they are intended for, so that CYCLE NN steps to the next iteration for <code>I</code> (as if it were a GO TO the END DO having its label as a suffix) while the EXIT XX exits both the numeric DO-LOOP and the DO-WHILE loop - without such labels only the innermost loop is affected and one can lose track. These labels must not be the name of any other entity in the source, and specifically not the name of the variable of the DO-LOOP concerned. Thus, if there are many DO I = 1,N loops, each must have its own label. There is unfortunately no equivalent to <code>NEXT I</code> as in BASIC instead of <code>END DO</code>so as to be clear just which DO-LOOP is being ended and for which index variable.
 
====Not returning at all====
In for example Fortran IV, as on the IBM1130, a <code>CALL EXIT</code> stopped the run, which is to say, it "exited" to the operating system. As distinct from STOP which stopped the flow by stopping the cpu. Another no-return was provided by the likes of <code>CALL LINK(PHASE2)</code> where PHASE2 was not a text string in quotes. This caused the flow of execution to abandon the current programme and the operating system would to load and run a programme called PHASE2. Code was loaded from low memory upwards, while storage in COMMON was assigned from high memory downwards and so long as desired data were not damaged by the new load, its processing would continue. Thus, if some data required a great deal of complex analysis and there was insufficient memory available to hold all the data plus all the code, it might be possible to split the processing into PHASE1 and PHASE2, etc.
 
===Interruptions to the flow===
More potent than RETURN is STOP, which ends the flow of execution there and then - without the need to signal some sort of "disaster" status so that each level of a nest of routines would return to its caller. Early Fortran also allowed STOP ''n'' where ''n'' was a number such as 303 and this value might be displayed on the computer's console display register in bright lights, or be printed in the job log, or on the standard output device. A later extension was STOP "message", but alas the message is only a fixed text, one can't devise a custom report such as "307 values! limit is 300"
 
Instead of STOP, there is PAUSE with the same syntax. The flow of execution would pause (that is, the entire computer would come to a stop in the days when one job only would run at a time), to be resumed with the next statement on the pressing of a button on the computer console for instance after the message "Attach output tape", or, ... the operator could via controls on the console inspect memory (on the decimal IBM1620, even floating-point numbers were easily parsed), modify memory, and cause execution to resume at some other (any other) chosen address...
 
===Flowcharts?===
A classic aid to design and analysis is a flowchart diagram, and there exist systems which will read the source code of a programme and draw its flowchart (on a graph plotter, say) with the various pieces of code appearing in blocks linked by lines showing the flow. Considering all the above, this is no simple challenge.
 
===Reaction===
There is a famous letter by Edsger Dijkstra's, titled ''Go To Statement Considered Harmful'', published in the March 1968 Communications of the ACM.
 
1,220

edits