Joined: 14 Jan 2008 Posts: 2504 Location: Atlanta, Georgia, USA
This is where nested EVALUATE's (introduced with VS/COBOL II) can replace 6-7 (or greater) nested IF levels ( Yikes ) and can come in real handy. As you say, the IF's just fall off the right side of the page/screen....
In the old days, if I was actually coding a case/evaluate structure, I would do it without the indenting, so it is clearer what it is:
IF condition a
IF condition b
IF condition c
IF condition d
No need anymore. No need for a genuine nested IF not to be indented.
One place I worked we somehow got hold of a fold-out paper Thanksgiving Turkey decoration (this was in the UK, which was why it was odd). If someone did something stupid (like Dick's example) you had to display the Turkey on top of your terminal for a week (or until superseded, whichever was shorter). Helped a little to concentrate minds.
For a real nested IF (or anything) how to avoid? If you are faced with a five-level nest where you need a change, it is not a happy sight.
One sort of nesting, PERFORMed paras/sections, don't march off to the right.
If you spend more time for the design of programm, you could avoid inscrutable code. The hidden secret of a good programm is the right mixture of segmentation and the strict use of conditional and unconditional branch instruction like Evaluate and Perform. I'm a hardliner. I won't see any normal move or compute instruction in the main programm-controll-section. I also use qualifier in section-names
which tells me the depth of a section within the programm-flow. The older one of us will remember the IBM SPL framework using A05/B05/F05 and so on.
The only legal commands for me in a control-flow-section are Perform, Evaluate and an IF-Then-Else, but not nested.
Perform Until Programm-End
......When ...Perform V05-Do-Something-02
......When ...Perform V05-Do-Something-03
......When ...Perform V05-Do-Something-04
......When other continue
I use the same design in assembler too. Keeping my programms strictly using this design it was quite easy for me in former times to modify some moduls just in the middle of the night after a telephone call, just after a few bottles of red wine and some houres with a horney blonde chick.
Oh god, lucky old days. Nothing is left over. Only the red wine.
In this method, you displace the nesting. From the normal nested structures to the sections. So, your PERFORMs become nested. I'm interested in your section-naming structure, which is the only way I've really identified to deal with this "problem" automatically, otherwise I end up thinking these (the performed sections) are now just too "deep" to be readily understandable. And then you think some more.
So, maybe you don't use the inline-perform like that. But the same thing is what is really happening from sections. What I mean is that when you are down at the third level, you also have to be aware of what was relevant at the first and seconde levels.
Don't get me wrong. I like your structure. It is the one I used, even. I'm as surprised as perhaps you are :-)
I'll (obviously) let UmeySan provide his own response as to how he would name the various sections, but this is how I would do it:
I assign 4-byte name prefixes that reflect both the hierarchical level of the section/paragraph (the first byte of the prefix (a letter)) and the order in which the section/paragraph was first referenced in the source (the second byte of the prefix (also a letter)); the third and fourth bytes of the prefix are numbers, which can be used to group related functions - e.g. for a given file, the last two prefix characters might be 10 for an OPEN, 20 for a START, 30 for a READ NEXT, 40 for a READ DIRECT, 50 for a WRITE, 60 for a REWRITE, 70 for a DELETE, and 80 for a CLOSE. The first two letters of the 'group' would be assigned in accordance with the 'normal' hierarchical/reference assignment logic.
The 4-byte prefix using this standard allows for 26 hierarchical levels and 2600 sections/paragraphs at each of those levels. FWIW, I normally assign I/O routines to hierarchical level 'X' and heavily referenced "utility" routines (e.g. display file-status error messages) to hierarchical level 'Z'.
The other thing I do is to always position the sections/paragraphs in the source in (ascending) prefix order. In this way, I always know where a referenced section/paragraph is located relative to the statement I am looking at - if the prefix is alphanumerically less than the current section/paragraph prefix, the referenced section/paragraph will be positioned earlier in the source; if greater, then later.
Also, VIEWing the source and executing
X ALL;F P'^' 8 ALL;F ' PERFORM ' ALL;X '*' 7 ALL
enables me to see the entire program structure at a glance (e.g. just what follows, minus the actual (non PERFORM) 'statements').
Etc. The numbers show one "axis", the letters another, the "depth" of the level of the performs (my "nesting"). As the letters "march off to the right" too much, I know to look at things again and simplify.
00- for program start-up
10- for opening files
80- for closing files
90- for program shut-down
99- for "routines" used from more than one section. I didn't distinguish IO from non-IO, (I was kind of lucky, and managed to avoid most IO directly) but that is a nice touch from Ronald.
IF I wanted to use a "GO TO" I would do 50AD-G-dfjksdf for the paragraph name, thus knowing that it was the target of a GO TO.
All the sections would be in strict sort-sequence. You always knew where to find in the listing, and you always knew what it was performed by (except for the general use 99-s).
In the XREF, all the procedure lables would be in order by line number. Particularly if there were GO TOs, you can look at the XREF and see that they are not outside the range.
I'd always make the names meaningful. You can get a lot in 30 characters, and if you go over, even, it is not the end of the world.
Any more favourites, anyone?
The other thing is maintaining other people's programs. I tended to stick to their convention, unless there was more time available than usual, when, in that lucky instance, the first thing I would do is to reformat my way.
I have an irrational dislike for SECTIONs. It came about from having to debug too many programs that mix paragraphs and SECTIONS improperly.
The thing is, how do you cater for idiots? The same person who adds a paragraph, after a SECTION, and performs the paragraph is probably going to add it in the middle of a perform thru as well. Or GO TO something that is not in the perform range.
OK, so you can get by without sections and without perform thrus. But then, if you can't, I definitely prefer sections. Even with no paragraphs in the section, I still code sections. Just in case, I suppose, or from habbit.
I'd sometimes idly think, why can't the compiler sort this out? "E" levels if you do dumb things. But too many earlier programs do dumb things, so "backwards compatability" loses out for everyone.
I'd like to see a compiler option like NOSH1, which, with the (T)est sub-parameter would highlight idiotic (outside of logical human readability scope) use of paragraph/section/go to - hey, for me, stick declaratives in as well if you like.
Funny thing is, for NOSH1(T), the OPT damn well knows about. List the generated code, look for any "non simple" returns anywhere, and then you know you have dodgy code in the program. Except declaratives. No idea how it handles that, but I suppose they are easy enough to spot anyway.
Naming convention for sections are still depending on personal advantages.
First, for my own, i make a difference between Control-Flow-Sections and real Processing-Sections. The real data-processing (move,compute,...) will only take place in these Processing-Sections. The logical flow of the data-processing within the programm ist guided by the Control-Sections.
I described it before. Ok, now naming conventions.
S00 Main Controll-Section of the Application
A00 Main Section for Programm-StartUp
V00 Main Section for Programm-Processing
Z00 Main Section for Programm-CleanUp
Whereas these sections are only Control-Sections witch perform others.
...Set Kto-Ind to 1
...Perform until Kto-Ind > Kto-Max
......move x to y
......set Kto-Ind up by 1
So, as you could see, the numer specifies the depth.
The first letter has a relationship to the kind of work.
A section named A45-blabla would be performed in section A40-blabla,
and will have a close link to A00. And this Section A45 has someting to do with the programm-Init. Same as Znn-Blabla. This section must have something to do with the Programm CeanUp at end of work.
Beside the A00, V00, and Z00 Main-Control-Sections i also have some universal sections for Open, Close, Write, or Declare Cursor, Fetch, Instert, Delete, etc.
So in any of my programms, Bnn-Sections will definitly deal with open dataset and Cnn will acordingly deal with close dataset.
If there's a B25, so it's a guideline, that this module opens five datasets.
B00 would be the Control-Sections for performing B05 till B25.
This Dataset would be read in Section R25 or written in Section W25
So as you see, there' quiet another kind of interrelationship.
Yes i know, perhaps it seams, something takes getting used to. But not for me. I'm used to it for the last 35 years. Whether Assembler, Cobol, Rexx, CSP, Abap.
And, at the end, i aggree with Dick, dbzTHEdinosauer.
Gotta love edit macro's and REXX Scripts
I have a little edit-rexx-proc which is executed by pressing a PF. The
Cursor has to be in a coding line. If there is a perform, pressing the PF will result in displaying the section. If the cursor is at a section-beginning, pressing PF will result in displaying all performs of this section. As a matter of course, this will also work for Assembler. Some more functions are included, but this will go beyond the scope of the discussion.
So, everyone of us has his own preferences and his own established-standards.
And i think, with every little new programm we are developping, our standard is expanding and ensuring the efficiency.