Every module is "structured" in form; moreover, the modules are not necessarily as tiny in size as the examples indicate, since a process box may contain an arbitrarily large one-in/one-out program.
There are several possible objections to such a style of programming:
(1) It requires recursion to implement loops in the flowchart.
- That's right. If your programming language won't support recursion (e.g. most FORTRAN implementations), you can't use this particular "structured, modular approach".
(2) Procedure calls are expensive.
- They shouldn't be!
(3) The chain of procedure calls will keep pushing stack, and the stack will overflow.
- This is true of current programming language implementations, but it has been shown above that such implementations use far more stack than necessary. If tail-recursive procedure calls are compiled as
JUMP
instructions, then this problem does not arise.
(4) This style of programming is unnatural: "That's not what procedures are for!"
- This is largely a matter of taste. I have written a number of medium-sized programs in this style (using a dialect of LISP) and find it quite natural for certain purposes. It accomodates itself well to "state-transition" kinds of programs. It also permits one to create non-standard looping constructs which are one-in/one-out, but which have complex relationships among the variables being stepped.
An additional observation should be made, of course: in the example above, the use of procedure calls hasn't endowed the program with any more structure than the use of flag variables or PROGRAM-COUNTER
did, compared with the GOTO
version. All it has done is possibly make the code more palatable. This may be a useful psychological illusion, but it is as much a myth as the belief that procedure calls are inherently expensive.
F. Procedure Calls and Modularity
The primary role which the procedure call plays in the current philosophy of programming discipline is as the agent of modularity. Similarly, the primary role played by GOTO
is as the agent of tangled flowgraphs.
I would like to suggest that our difficulties in dealing with programming and programming languages stem in part from a confusion between the abstract notions of program organization and the concrete embodiment of these notions as programming language constructs. In order to simplify our thinking we have attempted to enforce a one-to-one mapping between these two sets, and it doesn't work very well. For example, we decree that procedures are the method of producing modularity; that WHILE-DO
loops are the way to iterate; that IF-THEN-ELSE
is the way to produce conditionals; that GOTO
is the way to produce peculiar program structures.
The fact is that this just isn't so. Consider the notion of modularity, which is indeed a useful concept for organizing programs. While procedure calls are indeed a method of modularizing programs, there are other methods. The PL/I %INCLUDE
construct or the COBOL COPY
construct are one alternative. Another is the "PRINLEVEL
" feature in some LISP systems, which allows you to print the overall structure of a program while suppressing the detail of computations below a certain level of nesting. A third example (due to R. Zippel) is the common FORTRAN trick of breaking up a single complex assignment statement into several smaller ones: