COBOL

COBOL

COBOL

COBOL is responsible for the efficient, reliable, secure, and unseen day-to-day operations of the world's economy.

 View Only
Expand all | Collapse all

Considering Enterprise COBOL 5.2 "exit" enhancements

  • 1.  Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Wed May 25, 2016 04:11 PM

    So I've been pondering the new language features added with Enterprise COBOL v5.2, trying to come up with a good but not too contrived example of how they can be utilized.  I am specifically referring to the following new statements:

    • EXIT PARAGRAPH
    • EXIT PERFORM
    • EXIT PERFORM CYCLE

    While still slightly contrived, as most examples are, it's also fairly realistic.  My example demonstrates the following items:

    • An early exit from a paragraph if there is a condition where we know we don't actually want to execute the body of the paragraph.
    • We enter a loop where the following things occur:
      • There is invalid input, so we want to immediately iterate to the top of the loop (EXIT PERFORM CYCLE) and have the input re-entered.
      • We want to immediately exit the loop (EXIT PERFORM) without executing the remainder of the loop (when the command "end" is given).
      • We want to execute some specific code (each of the other WHEN conditions in the EVALUATE block) followed by some code ("display 'command complete'" in this case) that we'll execute no what valid command we have performed.
      • Additionally, after a valid command command has been entered and executed we want to immediately terminate the loop (the final EXIT PERFORM).

    While of course there are many ways to skin this particular set of cats Frown, including splitting things out in to separate paragraphs, etc., I think this is a fairly straight forward set of code.  And hopefully, once you are used to looking at the new statements/commands, pretty readable and understandable.

           identification division.       program-id. perf.       data division.       local-storage section.       77  dummy_exit_flag             pic x value low-value.           88  exited                        value space.           01  rc                          pic s9(4) binary value zero.       01  entry-id                    pic x(8).       01  command                     pic x(3).       procedure division.       processes section.       enter-processes.           accept entry-id           perform do_command           display 'bye!' upon console           move rc to return-code           goback.       do_command.           if entry-id = spaces               display 'invalid entry id' upon console               move 16 to rc               exit paragraph           end-if           display 'entry id = ' entry-id           perform until exited               display 'Enter command:' upon console               accept command from console               evaluate function lower-case(command)               when 'add'                   perform add-entry               when 'del'                   perform delete-entry               when 'chg'                   perform change-entry               when 'end'                   display 'exiting with no command performed'                           upon console                   move 4 to rc                   exit perform               when other              *> invalid command                   display 'invalid command!' upon console                   display space upon console                   exit perform cycle  *> loop               end-evaluate               display 'command complete' upon console               exit perform           end-perform           exit paragraph.       add-entry.           display 'adding entry ' entry-id upon console           *> more stuff goes here           exit paragraph.       delete-entry.           display 'deleting entry ' entry-id upon console           *> more stuff goes here           exit paragraph.       change-entry.           display 'changing entry ' entry-id upon console           *> more stuff goes here           exit paragraph.       end program perf.

    One thing I'm particularly fond of is the fact that we both "validate" and perform the valid commands within the same set of code, rather than having one set that validates (looping until the user enters a valid command) and then followed by the execution of the valid command.  This way if a new command is added we only have to insert the new command in to the single EVALUATE block.

     

     

    I also like how the "common code" that is executed when a valid (non-"end") command is entered is only in once place, rather than following each valid non-"end" command with the common code (or a perform of it).

    One thing I am not fond of is that COBOL does not offer an "infinite loop" construct (where really a loop is performed until it is explicitly exited outside of a "loop conditional".  In order to emulate this I had to create the dummy "dummy_exit_flag" field and its corresponding condition name "exited".  With latter of course being a contrived name because EXIT is a reserved word.  Obviously (to me!) it would be ideal if COBOL supported "PERFORM UNTIL EXIT" for this construct.  And the fact is, both Micro Focus COBOL and GnuCOBOL (née OpenCOBOL) support this obvious feature that was somehow overlooked or intentionally omitted (why?!) from even the latest COBOL standard.

    On the plus side, the compiler is smart enough to know that the "EXITED" condition will never be true, and thus it does not even check the UNTIL condition.  Which is exactly how "PERFORM UNTIL EXIT", if implemented, would behave.  (Can you guess I'm trying to get support for this enhancement, even though my RFE for it has already been declined? Laughing)

    All and any comments are welcome; but I would ask you have an open mind about all of it.

    Frank

    fswarbrick


  • 2.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Wed May 25, 2016 05:30 PM

    Does that "exited" work with OPT(1/2)?

    I think the "exit paragraph" where there is nothing going on except the paragraph being exited are superfluous. I suspect they wouldn't stand up to the OPTimizer.

    "exit something" is "GO TO somewherewithnoactuallabel" in disguise. Would you be happy with the code structure if you used GO TO label(s) to replace those? Was all the kerfuffle about "GO TO" just that it had a label?

    You do have individual paragraphs, and to my mind that is the only way "exit paragraph" should be even considered.

    You resist "exit paragraph" from within the EVALUATE or even PERFORM, but will "everyone"?

    Like with "GO TO", it will be possible to write programs which can be easily understood with the new "exit" options. Like with "GO TO" it will also be possible to write convoluted piles of junk. Unlike with "GO TO", the junkster will be able to say "I'm OK, I'm using a 'structured' concept, so my program is structured".

    Although the jury probably hasn't even been selected yet, I personally see grief ahead. Not with your programs, but with the less experienced coder, who rather than abandoning and rewriting a part of code they've already written, instead thy augment it with one of the new possible "exits", which either doesn't do what they think, or doesn't do what others reading the code may reasonably think.

    Never say "never", but I don't think I'll be using them when I have the choice.

    I'd be happy to shown to be pessimistic on this...

    BillWoodger


  • 3.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Wed May 25, 2016 06:42 PM

    Yes indeed, "exited" works at all OPTIMIZE levels.

    You are correct about the "superfluous" EXIT PARAGRAPH statements at the end of each paragraph.  They are optimized away, and that's exactly what I want.  I could have just used the old EXIT statement, and that's what I've been using, but the COBOL standard actually does not allow an EXIT to be in a paragraph with other statements.  While IBM COBOL has always eliminated this restriction, I figured I'd just go with EXIT PARAGRAPH to mark the end of each paragraph.

    Indeed "EXIT <something>" is just a "go to in disguise".  But then so is a PERFORM.  Using EXIT PERFORM [CYCLE] and EXIT PARAGRAPH allows you to eliminate any performing of sections (and really, sections altogether) and "perform...thru", the cause of many, many issues.

    I do not, in fact, resist an EXIT PARAGRAPH inside an EVALUATE (how is this any difference from IF [...] EXIT PARAGRAPH) or even within a PERFORM.  When appropriate I would in fact encourage it.  I simply didn't see a place for it within my example.  Now I see I could have done "exit paragraph" instead of "exit perform" for the "end" branch.  But in this case there was no need unless I wanted to avoid any code after the end-perform, in which case I would he happy to use it.  I hate what I think of setting and checking of "extraneous" flags.

    I am optimistic.  There will be resistance.  Possibly there will be misunderstandings (though perhaps not as much as you think).  I see these new things as ways to make code more readable, not less.

    Anyway, take a look at the code generated from this program.  I've elided the code for simply statements such as DISPLAY as it just clutters things and makes it harder to see the flow, which is really what we're looking at.  OPT(2), by the way.

       000148                     000002  L0009:    EQU     *                                          000148  9200 D128          000000            MVI     296(,R13),X'00'       #  DUMMY_EXIT_FLAG   00014C  E544 D0B8 0000     000000            MVHHI   184(,R13),X'0000'     #  RC                000152                     000002  USER-ENTRY: EQU     *                                        000152                     000014  PROCESSES: EQU     *                                         000152                     000015  ENTER-PROCESSES: EQU     *                                000016:  001400     accept entry-id                                                                [...]000017:  001500     perform do_command                                                                 000174                     000022  DO_COMMAND: EQU     *                                         000023:  002100     if entry-id = spaces                                                               000174  E340 D120 0004     000023            LG      R4,288(,R13)          #  ENTRY-ID              00017A  E340 3120 0021     000023            CLG     R4,288(,R3)           #  X'4040404040404040'   000180  A784 0092          000023            JE      L0010                                       000028:  002600     display 'entry id = ' entry-id                                                     [...]000029:  002700     perform until exited                                                               000196                     000029  L0015:    EQU     *                                           000030:  002800         display 'Enter command:' upon console                                          [...]000031:  002900         accept command from console                                               [...]000032:  003000         evaluate function lower-case(command)                                     0001C6  D203 D0C0 D0BC     000032            MVC     192(4,R13),188(R13)      0001CC  DC03 D0C0 33B8     000032            TR      192(4,R13),952(R3)       0001D2  5800 D0C0          000032            L       R0,192(,R13)          000033:  003100         when 'add'                                                                0001D6  C20F 8184 8440     000033            CLFI    R0,X'81848440'           0001DC  A784 0052          000033            JE      L0011                 000035:  003300         when 'del'                                               0001E0  C20F 8485 9340     000035            CLFI    R0,X'84859340'           0001E6  A784 003B          000035            JE      L0012                 000037:  003500         when 'chg'                                               0001EA  C20F 8388 8740     000037            CLFI    R0,X'83888740'           0001F0  A784 0024          000037            JE      L0013                 000039:  003700         when 'end'                                         0001F4  C20F 8595 8440     000039            CLFI    R0,X'85958440'     0001FA  A784 0010          000039            JE      L0014           000044:  004200         when other              *> invalid command         0001FE  1812               000045            LR      R1,R2              000200  18F4               000045            LR      R15,R4          000045:  004300             display 'invalid command!' upon console        [...]000046:  004400             display space upon console                     [...]000047:  004500             exit perform cycle  *> loop                 000050:  004800         exit perform                                       000216  A7F4 FFC0          000050            J       L0015              00021A                     000040  L0014:    EQU     *               000040:  003800             display 'exiting with no command performed'    [...]000042:  004000             move 4 to rc                                                          00022E  E544 D0B8 0004     000042            MVHHI   184(,R13),X'0004'     #  RC            000043:  004100             exit perform                                                          000234  A7F4 0046          000043            J       L0016                                     000238                     000038  L0013:    EQU     *                                      000038:  003600             perform change-entry                                                  00023A                     000064  CHANGE-ENTRY: EQU     *                                  000065:  006300     display 'changing entry ' entry-id upon console                               [...]000067:  006500     exit paragraph.                                                               000258  A7F4 0078          000038            J       L0017                                     00025C                     000036  L0012:    EQU     *                                      000036:  003400             perform delete-entry                                                  00025E                     000059  DELETE-ENTRY: EQU     *                                  000060:  005800     display 'deleting entry ' entry-id upon console                               [...]000062:  006000     exit paragraph.                                                               00027C  A7F4 0066          000036            J       L0017                                     000280                     000034  L0011:    EQU     *                                      000034:  003200             perform add-entry                                                     000282                     000054  ADD-ENTRY: EQU     *                                     000055:  005300     display 'adding entry ' entry-id upon console                                 [...]000057:  005500     exit paragraph.                                                               0002A0  A7F4 0054          000034            J       L0017                                     0002A4                     000024  L0010:    EQU     *                                      000024:  002200         display 'invalid entry id' upon console                                   [...]000025:  002300         move 16 to rc                                                             0002B8  E544 D0B8 0010     000025            MVHHI   184(,R13),X'0010'     #  RC            000026:  002400         exit paragraph                                                            0002C0                     000043  L0016:    EQU     *                                      000052:  005000     exit paragraph.                                                            000018:  001600     display 'bye!' upon console                                                   [...]000019:  001700     move rc to return-code                                                     0002D8  4820 D0B8          000019            LH      R2,184(,R13)          #  RC            0002DC  4020 8018          000019            STH     R2,24(,R8)            #  RETURN-CODE000020:  001800     goback.                                                                    [...]   000348                     000047  L0017:    EQU     *                                      000049:  004700         display 'command complete' upon console                                   [...]   00035C  A7F4 FFB2          000050            J       L0016                                  
    1. Start with label L0009, where local storage (including my dummy_exit_flag) is initiated
    2. Paragraph do_command is "inlined" by the compiler.
    3. if entry-id is spaces we jump to L0010.
    4. The PERFORM loop starts at L0015.  There is no checking of the dummy_exit_flag (exited condition).
    5. Each of the 3 "action" WHEN conditions, when true, cause a simply jump to the appropriate label (add=L0011, del=L0012, chg=L0013).  These labels execute their code and then jump to L0017.
    6. The "when 'end'" condition jumps to L0014, which executes its code than then jumps to L0016.
    7. The "when other" condition executes its code and then drops through to the code to jump to L0015, the top of the perform loop.
    8. L0017, which is where we end up after performing any of the primary actions, simply executes its code and then jumps to L0016 (the same place that "when 'end'" jumped to), which is the (unnecessary) exit paragraph (end of do_command), which then does the setting of RETURN-CODE and the GOBACK.

    I think I have that all right.  And it all looks very good to me; in fact very close to how I might code it if I were using assembler directly.

    fswarbrick


  • 4.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Thu May 26, 2016 08:40 PM

    Yes, I with the "exited" I was forgetting that the compiler will excise code you can never get into, but is unable to know about code that theoretically (or even practically) you may/can never be able to get out of :-)

    If you think a PERFORM is a GO TO, I think you've missed the point.

       
        THE-LOOP.

              perform until exited
                   display 'Enter command:' upon console
                   accept command from console
                   evaluate function lower-case(command)
                   when 'add'
                       perform add-entry
                   when 'del'
                       perform delete-entry
                   when 'chg'
                       perform change-entry
                   when 'end'
                       display 'exiting with no command performed'
                               upon console
                       move 4 to rc
                       GO TO LOOP-END
                   when other              *> invalid command
                       display 'invalid command!' upon console
                       display space upon console
                       GO TO THE-LOOP
                   end-evaluate
                   display 'command complete' upon console
                   GO TO LOOP-END
               end-perform

        LOOP-END.

     

    The "exit something" allows that code to work in a single paragraph, without having to create labels. The compile knows where ot "GO TO", but *does the reader always know* (which is more important than the compiler knowing, it always knows, accurately,it is just that there can be conflict with what the user, in error, expects).

    However, there is no need for you to have used the initial PERFORM, you could have in-lined it yourself, then all the GO TOs work with no further changes.

    For your PERFORM, there is never a "normal" cycle. If execution reaches the end of the block, the PERFORM is exited. There is only another iteration if the "current cycle" is interrupted.

    I think this construct better represents what you have:

     

               PERFORM
                  ACCEPT W-INPUT
                  IF NOT W-PROCESS-INPUT
                      CONTINUE
          *           EXIT PERFORM CYCLE
                  END-IF
                  PERFORM PROCESS-INPUT
               END-PERFORM

    (CONTINUE because I don't have access to V5.2 :-) ).

     

    Of course, those are deficiencies of an artificial example.

    What if someone adds a SECTION after your existing code, and uses EXIT SECTION to get to it? Or uses EXIT SECTION without adding a SECTION?

        some-label.
             do some stuff
             do something else
             do a third type of thing

    At a site where the use of GO TO is "forbidden", someone who needs to avoid "do something else" does this:

        some-label.
             do some stuff

             if some-condition
                 exit paragraph
             end-if
             do something else

        some-other-label.
             do a third type of thing

    Someone later picks up the code, notices that "some-other-label" is not referenced (I'm assuming here that it is not noted as referenced in the compile listing simply due to the "exit paragraph") and removes it. The code still compiles, although the "some-other-lable" was absolutely 100% vital to the program "working".

    We've noted the use of "exit paragraph" in a PERFORM ... THRU ... before. Sites that mandate the use of an "exit paragraph" (needing the THRU) and who don't forbid the use of more than two paragraphs in that range, are asking for trouble.

    I apologise for assuming you wouldn't just fly directly out of an EVALUATE via "exit perform" or even "exit paragraph/section" :-)

    Would you do that prior to V5.2 with GO TO? If not, why would you do that just because the GO TO is disguised?

    Now, simply being able to use GO TO doesn't of itself lead to spaghetti code. It was the *way* that people, in practice, used GO TO. "exit something" is just a GO TO, without a label. There is nothing intrinsic which prevents its "abuse" ("well, if I just use an 'exit paragraph' here I don't have to even consider if the code could be restructured to make the program easier to understand now that it is doing something different").

    A more subtle spaghetti, perhaps, but is that good?

    Highlighting what would be "good practice" in using these "exit somethings", and what would be "bad practice", would perhaps help to favour the first over the second. But, you know when we get down to that in COBOL it is always difficult to get agreement on what is what.

    By choice I don't use "GO TO". I therefore have no need of a disguised GO TO to make my programs "clearer". I have no "best practice" use for it.

    So the people who do use GO TO have to set out the "best practice" for it. Leaving the people who don't think GO TO is good practice... if a GO TO is needed, then, for me, it is best as a GO TO. At least if someone removes the target label it won't compile. If someone is considering adding code/label in the vicinity, at least they can readily see what is affected.

    So, for me, exit perform/exit perform cycle/exit paragraph/exit section are bad practice. If you find yourself "having" to use one, use a GO TO.

    OK, exit perform cycle may be considered differently (in a more realistic example, a label prior to an in-line PERFORM isn't going to cut it). But I code happily without feeling the need of it, so why would that suddenly change because it is available? For example, would you encourage a multi-page in-line PERFORM with several "exit perform cycle"s in it?

    I think if you can set out some "best practice for use of exit something" theory, so that it can be applied to general practical examples, the discussion becomes more useful. That will certainly be better than just letting its use develop "organically".

    We may have to come up with a snappier name (there are other "exits" which is entirely separate from this particular discussion as well).

    BillWoodger


  • 5.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Thu June 23, 2016 08:38 PM

    Some day I will continue my personal thoughts, but for now the following is an interesting discussion (where you see 'break' think "EXIT PERFORM" and where you see 'continue' think "EXIT PERFORM CYCLE"):

    http://programmers.stackexchange.com/questions/58237/are-break-and-continue-bad-programming-practices

    Cool

    fswarbrick


  • 6.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Sun June 26, 2016 04:11 AM

    You want me to wade through 19 answers and associated comments, from non-Mainframers?

     

    On my rapid survey (scrolling) I did spot a "single-exit-point"er, and "tools in the bag". The Accepted answer seems to pull both ways. I doubt there's really much that is new in that discussion.

     

    The people who jump on any form of GO TO as "making the code clean because the only other possibility is nested ifs and complex, repeated control-structures" always confuse me. I don't have huge EVALUATEs or deep nested-IFs or repetitions of tests and I don't use GO TO (or any of its forms - unless we are still counting PERFORM as a GO TO, I use PERFORM a lot).

     

    Remedial action is not easy (read possible) to suggest on a "snippet" in isolation. In the full context, the solution is always easy. Design before you code.

     

    Yes, that also means when changing code. That thing that doctors do, "don't make it worse". Same thing for programming, but, in programming, there is this hazy issue over what "making it worse" actually means :-)

     

    A program can look as ugly as all heck, with tubes sticking out everywhere, unable to walk, digest food, think and reason for itself and all those things, but if it still, mostly, produces the correct answer, keep it alive. Bang in another GO TO, make the code a bit cleaner.

     

    I'm not saying you should rewrite everything (or touch anything which is outside the scope of the spec.) but I am saying there are ways to make clean changes to bad code without using GO TO. (if the client demands GO TO, of course they get it).

     

    I am saying that the arguments for using GO TO (in all its guises) are largely fake. They set up a "Straw Man" - "if you don't use GO TO your code can only be like this <insert some horrible practice here>" and then proceed to set fire to it in the name of "GO TO is good to avoid letting that happen". They are not actually arguments for using GO TO, they are arguments against what they regard as a mythical possibility, that you can write good, understandable, easily maintained, clear, performant and all-round utterly nice programs without using GO TO.

    This discussion (of GO TO-including-guises) may be one of the few things which outlives COBOL.

     

    Lucky me. I returned to the link, and found this comment on what is listed (for me) as the second answer:

    Make your functions small. Then make them smaller" -Robert C. Martin. I found that this works surprisingly well. Every time you see a block of code in a function that needs a comment explaining what it does, wrap it into a separate function with a descriptive name. Even if it is only a few lines, and even if it is only used once. This practice eliminates most of the issues with break/continue or multiple return

       
    BillWoodger


  • 7.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Mon June 27, 2016 08:43 PM

    How about a more realistic example.  While technically not "real code" (which would be too long), the following shows how an existing program essentially is coded.  Well, the existing program uses sections and GO TOs, and I have replaced those with using EXIT PARAGRAPH.  (See my comment at the bottom regarding why I use "EXIT PARAGRAPH" also to explicitly terminate each paragraph.)

     1000-PROCESS-INPUT.     PERFORM 1100-VALIDATE-INPUT     IF INPUT-ERROR         PERFORM 1900-DISPLAY-ERROR     ELSE         PERFORM 1200-SAVE-INPUT     END-IF     EXIT PARAGRAPH. 1100-VALIDATE-INPUT.     IF NOT FIELD-1-VALID          SET INPUT-ERROR TO TRUE         MOVE 'FIELD 1 MUST BE X, Y OR Z' TO MAP1-MESSAGE-O         MOVE DFHRED TO MAP1-FIELD1-C         MOVE CURSOR-PTR TO MAP1-FIELD1-L         EXIT PARAGRAPH     END-IF     IF NOT FIELD-2-VALID          SET INPUT-ERROR TO TRUE         MOVE 'FIELD 2 MUST BE 1, 2 OR 3' TO MAP1-MESSAGE-O         MOVE DFHRED TO MAP1-FIELD2-C         MOVE CURSOR-PTR TO MAP1-FIELD2-L         EXIT PARAGRAPH     END-IF     [... 7 more "IF NOT" blocks similar to the above ...]     IF NOT FIELD-10-VALID          SET INPUT-ERROR TO TRUE         MOVE 'FIELD 10 MUST BE ...' TO MAP1-MESSAGE-O         MOVE DFHRED TO MAP1-FIELD10-C         MOVE CURSOR-PTR TO MAP1-FIELD10-L         EXIT PARAGRAPH     END-IF     EXIT PARAGRAPH. 1200-SAVE-INPUT.     [...]     EXIT PARAGRAPH.  1900-DISPLAY-ERROR.     [...]     EXIT PARAGRAPH.

    Basically, once you get input that is not valid you no longer want to validate the rest of the data.  You highlight the field in error, place the cursor at that position, and write the error message.  This is a CICS application which doesn't really have room for multiple error messages.  With a "GUI" type application you may want to go ahead and validate everything and show multiple error messages, but in this case you really can't do that.

    So what is the point in, say, checking the INPUT-ERROR condition for the remaining fields.  Even if you placed the logic to edit each field within its own paragraph you'd still have a lot of "IF NOT INPUT-ERROR THEN PERFORM ...".  Certainly this is a perfectly valid thing to do, and I've seen it.  And I've hated it!  Grin

    I do want to mention that I am all for "very small procedures/functions".  In fact I generally encourage them very much.  And yes, there are a lot of cases where instead of doing something like

     1000-DO-SOMETHING.     IF INVALID-DATA         EXIT PARAGRAPH     END-IF     [... CODE HERE FOR HAPPY PATH ...]     EXIT PARAGRAPH.

    You could do this:

     1000-DO-SOMETHING.     IF INVALID-DATA         CONTINUE     ELSE         PERFORM 1001-REALLY-DO-SOMETHING     END-IF     EXIT PARAGRAPH. 1001-REALLY-DO-SOMETHING.     [... CODE HERE FOR HAPPY PATH ...]     EXIT PARAGRAPH.

    This is perfectly valid, and in some cases very worthwhile.  But look at the stupid paragraph name I had to make just because I did it this way.  I just don't see the point. 

    Obviously I could have also just put the "happy path code" directly inline instead of doing the PERFORM at all.  But I like to keep my code within IF/EVALUATE blocks as small as possible (imagine the happy path code being 20+ lines).  I'm thinking you agree with this philosophy as well.

    -----------

    Why I explicitly terminate each paragraph with "EXIT PARAGRAPH."

    Within the procedure division I only use periods when absolutely required by the COBOL standard.

    • I don't like to place a "terminating period" just on the last executable statement of a paragraph because if I later add additional statements I either
      • have to remove it (making the source code compare look like I changed something relevant, when I didn't)
      • have to leave it, in which case it blows away my "only use them when needed".
    • I don't like to use "EXIT." (though up to this point I have often violated this) because, even though Enterprise COBOL (and predecessors) allow it, the COBOL standard days that EXIT must be the only statement within its enclosing paragraph.
    • I don't like to use "CONTINUE." because this makes it look like the program flow continues to the next paragraph; when generally it does not.
    • I don't like to use "." (a period by itself) because its hard to read and just plain flugly.

    For all of these reasons I've made my own rule that I will terminate each paragraph with "EXIT PARAGRAPH".  The compiler is smart enough to not generate any extra code.  And in fact this helps with the debugger in that there is a "final statement" for it to position after executing the last "executable statement", rather that taking you to the beginning of the next statement after the "PERFORM" that got you to the paragraph.

    Your mileage may vary!

    Frank

     

    fswarbrick


  • 8.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Tue June 28, 2016 02:21 AM

    Unfortunately the specific example is a simple EVALUATE with PERFORM for each WHEN. Even if this is 300 pages long (OK, 256 WHEN's, OK 200 WHEN's so you don't approach the limit and have to restructure for a "one line change") there is no difficulty in following it (because the blocks of code aren't included).

    I agree about the full-stops/periods. However, I use the singular full-stop/period in column 12. Both EXIT and CONTINUE do also give you stepping-points and "collecting" points (for the LIST output, there's no concern that the final verb in the paragraph/SECTION actually needs all that stuff attached to it).

    BillWoodger


  • 9.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Tue June 28, 2016 01:29 PM

    EVALUATE does not work in this case.  The logic is to perform validation of ALL fields until all fields have been validated, or until the first validation failure.

    EXIT and CONTINUE do work, but I'm going to use EXIT PARAGRAPH anyway.

    fswarbrick


  • 10.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Mon July 11, 2016 06:48 AM

    Sorry for the very late reply.

         1100-VALIDATE-INPUT..

            EVALUATE TRUE

               WHEN  NOT FIELD-1-VALID
                  PERFORM .... *> to keep it neat and short

               WHEN NOT FIELD-2-VALID
                  PERFORM .... *> to keep it neat and short
                [  ... 7 more WHEN blocks similar to the above ...]

                WHEN  NOT FIELD-10-VALID

                  PERFORM .... *> to keep it neat and short

                WHEN OTHER
                   PERFORM ... *> all is good with the validation

            END-EVALUATE

        *> arrives at this point in all circumstances, if that is needed

            .

        next-paragraph.

     

    I don't see why that isn't equivalent. Exach test will be attempted, if none are true the OTHER will be actioned. As soon as one is true, no more tests are done and control will be transferred to after the END-EVALUATE. You go out of your paragraph directly from within the IFs, the above just by not having any code after the END-EVALUATE.

     

    Note that your IF after the PERFORM can become redundant (by using the OTHER).

     

    Note that the optimiser is likely to "in-line" the PERFORMs, so the actual generated code is going to be very similar. Your IFs could contain PERFORMs as well and the same would happen.

     

    It's a different issue when you want to higlight all the screen errors at once (which is usual in my experience) but then that woulnb't demonstrate the potential usage of the EXIT PARAGRAPH. There you need an extra condition to get the cursor set only if it is not set already.

    BillWoodger


  • 11.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Wed August 10, 2016 06:03 PM

    I only just saw this reply.

    My attempt to make a simplistic example of my thought has failed me once again.  Here is some real life code (modified to use EXIT PARAGRAPH instead of GO TO section-exit):

     2210-CHECK-EDITS.                                              PERFORM 2106-RESET-ATTRB                                   IF BKCOMM-BK3-ITEM NUMERIC                                     IF BKCOMM-BK3-ITEM > BKCOMM-BK3-ITEMS-THIS-PAGE              OR BKCOMM-BK3-ITEM < 1                                       SET INPUT-ERROR TO TRUE                                    MOVE 'INVALID ITEM NUMBER' TO BKP3M-MESSAGEO               MOVE DFHRED TO BKP3M-ITEMC                                 MOVE CURSOR-PTR TO BKP3M-ITEML                             EXIT PARAGRAPH                                         END-IF                                                 END-IF                                                     IF BKCOMM-BK3-ACTION = LOW-VALUES OR SPACES                        CONTINUE                                                   ELSE                                                               MOVE BKCOMM-BK3-ACTION TO WS-EDIT-ACTION                       IF VALID-ACTION                                                    IF WS-EDIT-ACTION = 'PAYX'                                         IF LATE-APPROVAL-PASSWORD                                          CONTINUE                                                   ELSE                                                               SET INPUT-ERROR TO TRUE                                        MOVE                                                            'VALID ONLY UNDER LATE APPROVAL PASSWORD'                          TO BKP3M-MESSAGEO                                         MOVE DFHRED TO BKP3M-ACTIONC                                   MOVE CURSOR-PTR TO BKP3M-ACTIONL                               EXIT PARAGRAPH                                             END-IF                                                     END-IF                                                     ELSE                                                               SET INPUT-ERROR TO TRUE                                        MOVE 'INVALID ACTION' TO BKP3M-MESSAGEO                        MOVE DFHRED TO BKP3M-ACTIONC                                   MOVE CURSOR-PTR TO BKP3M-ACTIONL                               EXIT PARAGRAPH                                             END-IF                                                     END-IF                                                         IF BKCOMM-BK3-ITEM NUMERIC                                      IF BKCOMM-BK3-ACTION > SPACES                                   IF ACTION-ADD-ITEM                                              SET INPUT-ERROR TO TRUE                                     MOVE 'DO NOT ENTER ITEM FOR ADD ACTION'                       TO BKP3M-MESSAGEO                                         MOVE DFHRED TO BKP3M-ITEMC                                  MOVE CURSOR-PTR TO BKP3M-ITEML                          ELSE                                                            SET ITEM-SELECTED TO TRUE                               END-IF                                                  ELSE                                                            SET INPUT-ERROR TO TRUE                                     MOVE 'PLEASE SELECT AN ACTION FOR THIS ITEM'                  TO BKP3M-MESSAGEO                                         MOVE DFHRED TO BKP3M-ACTIONC                                MOVE CURSOR-PTR TO BKP3M-ACTIONL                        END-IF                                                      EXIT PARAGRAPH                                ELSE                                                            IF BKCOMM-BK3-ACTION > SPACES                                   IF ACTION-ADD-ITEM                                              IF BKCOMM-BKP3-ACCT-X > SPACES                                  SET ITEM-ADD TO TRUE                                    ELSE                                                            SET INPUT-ERROR TO TRUE                                     MOVE 'PLEASE SELECT AN ACCOUNT TO ADD'                        TO BKP3M-MESSAGEO                                         MOVE DFHRED TO BKP3M-ACCTC                                  MOVE CURSOR-PTR TO BKP3M-ACCTL                              EXIT PARAGRAPH                                          END-IF                                                  ELSE                                                            SET INPUT-ERROR TO TRUE                                       MOVE 'PLEASE SELECT AN ITEM FOR THIS ACTION'                    TO BKP3M-MESSAGEO                                           MOVE DFHRED TO BKP3M-ITEMC                                                   BKP3M-ACTIONC                                  MOVE CURSOR-PTR TO BKP3M-ITEML                                EXIT PARAGRAPH                                            END-IF                                                    END-IF                                                    END-IF                                                        IF BKCOMM-BK3-INIT = LOW-VALUES OR SPACES                           CONTINUE                                                    ELSE                                                                SET INPUT-ERROR TO TRUE                                         MOVE 'INITIALS NOT VALID HERE WITHOUT ITEM AND ACTION'            TO BKP3M-MESSAGEO                                             MOVE DFHRED TO BKP3M-INITC                                      MOVE CURSOR-PTR TO BKP3M-INITL                                  EXIT PARAGRAPH                                              END-IF                                                          [...there's actually a bit more, but I hope this makes enough of a point...]

    Can this be made in to a single fairly long EVALUATE?  Perhaps.  Would it be more readable?  I don't believe so.  But you are welcome to try!  Smile

    Frank

    fswarbrick


  • 12.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Wed August 10, 2016 06:19 PM

    Before you reply, Bill, I think you me have converted me (to some degree).  I'm going to post a version similar to what you have above.  Wait for it!

    fswarbrick


  • 13.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Thu August 11, 2016 02:05 AM

    OK. We could just remove those two posts to tidy things up.

    BillWoodger


  • 14.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Thu August 11, 2016 11:44 AM

    I wouldn't dream of it, Bill.  You deserve credit for pushing me, even if I wanted to strangle you at times!  Which is not to say I absolutely agree with you on the total lack of need (I believe is your opinion) of the "enhanced exits", but I am coming closer to believing they are only desirable in rather exceptional cases.

    In any case, look how simple my code is now, thanks to your advice.

     2210-CHECK-EDITS.                                           PERFORM 2106-RESET-ATTRB                                MOVE BKCOMM-BK3-ACTION TO WS-EDIT-ACTION                                                                        EVALUATE TRUE                                           WHEN BKCOMM-BK3-ITEM NUMERIC                             AND (BKCOMM-BK3-ITEM > BKCOMM-BK3-ITEMS-THIS-PAGE            OR BKCOMM-BK3-ITEM < 1)                               PERFORM INVALID-ITEM-NBR                            WHEN WS-EDIT-ACTION = 'PAYX'                             AND NOT LATE-APPROVAL-PASSWORD                             PERFORM LATE-APPROVAL-REQUIRED                      WHEN NOT VALID-ACTION                                       PERFORM INVALID-ACTION                              WHEN BKCOMM-BK3-ITEM NUMERIC                             AND BKCOMM-BK3-ACTION > SPACES                             PERFORM ITEM-WITH-ACTION                            WHEN BKCOMM-BK3-ITEM NUMERIC                                PERFORM SELECT-AN-ACTION                            WHEN ACTION-ADD-ITEM                                     AND BKCOMM-BKP3-ACCT-X > SPACES                            PERFORM SELECT-AN-ACCOUNT                           WHEN ACTION-ADD-ITEM                                        PERFORM EDIT-ADD-ITEM                               WHEN BKCOMM-BK3-ACTION > SPACES                             PERFORM SELECT-AN-ITEM                              WHEN BKCOMM-BK3-INIT >  SPACES                              PERFORM INITIALS-NEED-ITEM-AND-ACTION               WHEN BKCOMM-BKP3-ACCT = LOW-VALUES                          PERFORM 2105-SET-REFRESH                            WHEN OTHER                                                  PERFORM ACCOUNT-ONLY                                END-EVALUATE                                            EXIT.                                             

    Interestingly, I often use this style now without a second thought.  But the code I posted previously (except having used GO TO instead of EXIT PARGRAPH) is almost 20 years old, and is part of my first large project as a COBOL programmer.  So I have some excuse.  Grin

    But this new code is so "worthy" I am almost tempted to implement it in to production.

    Frank

    fswarbrick


  • 15.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Sat August 13, 2016 05:39 AM

    I can't resist this slightly tongue in cheek program.

    program-id. 'validate'.data division.working-storage section.01  bad-field pic x.01  bad-value pic x.linkage section.01  result pic x.    88  good-result value '1'.    88  bad-result value zero.01  a pic x.    88  a-is-valid values 'A' 'a'.01  b pic x.    88  b-is-valid values 'B' 'b'.01  c pic x.    88  c-is-valid values 'C' 'c'.procedure division using result a b c.    evaluate false    when a-is-valid        move 'A' to bad-field        move a to bad-value    when b-is-valid        move 'B' to bad-field        move b to bad-value    when c-is-valid        move 'C' to bad-field        move c to bad-value    when other        set good-result to true        display 'all is well'        exit paragraph    end-evaluate    set bad-result to true    display 'invalid value for' space             bad-field ':' space            bad-value    goback.end program 'validate'.

     

    fswarbrick


  • 16.  Re: Considering Enterprise COBOL 5.2 "exit" enhancements

    Posted Sat August 13, 2016 07:42 AM

    Not tongue-in-cheek at all. This is a variation of the case where, for instance, you have multiple inputs on a screen, and rather than annoying the user by validating only to the first incorrect field, and then when they fix that, tell them there is another wrong, you validate all the fields and stick the cursor on the first that is incorrect. This I referred to earlier in the topic. This does not suit EVALUATE, although your example does:

     

        evaluate false
        when a-is-valid
            move 'A' to bad-field
            move a to bad-value
            perform result-is-bad
        when b-is-valid
            move 'B' to bad-field
            move b to bad-value
            perform result-is-bad
        when c-is-valid
            move 'C' to bad-field
            move c to bad-value
            perform result-is-bad
        when other
            perform result-is-good
       end-evaluate
     

    With the two PERFORMed paragraphs (or SECTIONs) containing the remaining code.

    BillWoodger