rb@ccird1.UUCP (Rex Ballard) (06/07/86)
In article <1006@dataioDataio.UUCP> bright@dataio.UUCP (Walter Bright writes: >In article <2823@utcsri.UUCP> greg@utcsri.UUCP (Gregory Smith) writes: >>>> o Any sort of multi-level break statement. There is no syntacticly clean >>>> way of adding this to C. >>>C already has a multi-level break statement. It's spelled "goto." >>>Putting a goto in a costume doesn't disguise it. >>When a human reading a program sees 'break', it is immediately known >>that the current loop is being abandoned. In order to determine the >>effect of a goto, you have to find its destination. If you don't >>believe there is a big difference, try maintaining someone else's >>BAS*C code sometime. > >There's no problem finding where a goto goes to if you have only one or >two in a function. Gotos only become a problem when you have a snarl >of them. What I find confusing is four page functions, with 47 levels >of ifs and {}s, and trying to figure out where control flow goes when a >break happens. You have to count }s, or run a listing and connect the >{}s with a pen. ICK!!! 47 levels of ifs and {}s in the SAME FUNCTION??!!??!! > >I've had people do greps for gotos on my code, show me an out-of- >context list of the 14 they found in 10,000 lines of C, and tell me >that my code was bad. Please don't tell me you mean 10,000 lines in the same function. >Using only structured programming constructs only guarantees that the >flow graph for your program will be reducible, it doesn't guarantee >that your program is structured. The only purpose to having a reducible >flow graph is if your optimizer can't handle irreducible ones. Obviously, "structured programming" and "structured design" have not yet been integrated :-). One of the painful beauties of FORTH is that it is nearly impossible to write one LONG function when several SHORT ones would make the who task easier to understand. Even without the "16 line block" editor, it is hard to get past 10 or 15 statements without "loosing the stack". Unfortunately, C is much more "structured", which makes it much easier to write one function that "initializes the world" in-line. As any good C programmer why he doesn't "break it down" a little, he'll tell you "it would slow things down". OK how about a nice "quick call" or "gosub", or something that would be optimized to not do the frame saves? Another common "trick" is to write a big huge case statement where each case contains nearly identical code an let the "-O" option break the whole thing into hundreds of little "subroutines and jumps". The most common use for "gotos" is a "switch inside a loop which needs to execute the common code on two or more conditions". The examples usually look so trivial that the solutions appear obvious to everyone. The someone point out that the example is a simplification of some monster program. Of course, if you have "hundreds of little functions" running around, you now need a associative database to keep track of what the cryptic names really mean and who calls who, right? The solution involves not just the Compiler, but the Assembler/Linker too. By using "real" names instead of "glyphs" and having the Compiler/Assembler/Linker produce a "system data-base" indicating the type, caller-callee relationship, source file, and "mnemonic equivalent" of globals. Cflow with the '-g' option gives the caller-callee database, source file and line#, and some typing. Here's one "simple" way to maintain compatibility. Maintain a "compler linkage table" that allows the compler to generate/resolve Global lables in much the same way it currently treates local and static lables. This, in effect means having "front-end" linkage to get referrences for library routines, perhaps in the form of a "dynamic include file". In short, instead of making C just a good "structured programming" language, make it a good "structured design AND programming" language. Additional Ideas?