Code Comments
Programming Forum and web based access to our favorite programming groups.William M. Klein<wmklein@nospam.netcom.com> 02/08/07 8:41 PM >>> >WithOUT getting into the whole procedural vs OO debate, the recent posts in >this thread really DO remind me of "highly-modularized" procedural code that was >becoming semi-common in the late 80's and 90's (before COBOL lost its >"glitter"). In several IBM mainframe shops (which is what I knew best in those >days), the use of dynamic CALL statements with sub-programs with procedure >division that "could print on a single page of laser paper" gained a certain >(good and bad) reputation. OBVIOUSLY, the same goal of "encapsulating" logic >(and reuse of existing logic) was behind this. > >It may or may not have anything to do with why OO hasn't caught on with IBM >mainframers, but the "highly-modularized" approach turned out to be a VERY bad >decision for some shops that were early implementors of IBM's LE (and, yes, I >still think it is similar to .NET CLR). In early IBM LE environments, the >overhead for doing "dynamic CALL" statements in COBOL was HORRENDOUS (especially >between old and new programs). Therefore, these "highly modularized" >applications came to screaming halts in actual mainframe production >environments. No change to code, just to run-times. (FYI, this has improved in >recent years. See LE "XPLINK" for example) > >This may (or may not) have anything to do with why mainframers are "hesitant" to >move to many classes with small method applications. > >(Just my $.02) I am still a fan of 'shared subroutines', though with some caveats. Performance is not one of them, though. I've never done any empirical testing, but I've never noticed much in the way of performance degradation when using them. In any case, my biggest problem with using them is lack of flexibility when "extending" them. Let me give a real world example... We have a subroutine called TXND. It's goal is to take in "transaction data" from a database and return a formatted transaction description. 01 TXND-SUBROUTINE PIC X(8) VALUE 'TXND'. 01 TXND-LINKAGE-AREA. 05 TXND-PASSED-DATA. 10 TXND-CALLER-ID PIC X(8). 10 TXND-CURRENT-SUBROUTINE PIC X(12). 10 TXND-COMPRESS-LINE-SW PIC X. 88 TXND-COMPRESS-LINES VALUE 'Y'. 10 TXND-1LOC-DESC-SW PIC X. 88 1LOC-DESC-WANTED VALUE 'Y'. 10 TXND-MSTR-SEGMENT PIC X(1500). 10 TXND-TRAN-SEGMENT PIC X(50). 10 TXND-DESC-SEGMENT PIC X(55). 05 TXND-RETURNED-DATA. 10 TXND-SHORT-DESC PIC X(10). 10 TXND-LONG-DESC-1 PIC X(75). 10 TXND-LONG-DESC-2 PIC X(75). 10 TXND-LONG-DESC-3 PIC X(75). 10 TXND-SHORT-DESC-NUM PIC 9(9). 10 TXND-CONVERTED-CHECK-SW PIC X. 88 TXND-CONVERTED-CHECK VALUE 'Y'. 10 TXND-ICM-TRAN-TYPE PIC X(10). 10 FILLER PIC X(50). PROCEDURE DIVISION. * after retreiving the "master segment", a "transaction segment" and a "transaction 'description' segment" from the database. * (the transaction description segment is really just an extension of the transaction segment with additional information that is needed for some, but not all, transactions) MOVE DMDMSTR TO TXND-MSTR-SEGMENT MOVE DMDTRAN TO TXND-TRAN-SEGMENT MOVE TRANS-DESCRIPTION-SEGMENT TO TXND-DESC-SEGMENT MOVE 'CICSDD11' TO TXND-CALLER-ID MOVE 'N' TO TXND-COMPRESS-LINE-SW MOVE 'N' TO TXND-CONVERTED-CHECK-SW CALL TXND-SUBROUTINE USING TXND-LINKAGE-AREA Originally when this subroutine was designed the 05 level TXND-RETURNED-DATA did not include the TXND-CONVERTED-CHECK-SW and TXND-ICM-TRAN-TYPE fields. When these were added later it required a recompile of every program that called this subroutine, even if those programs did not care about the new fields. Obviously this is the reason for the now 50 bytes of filler. But of course 50 bytes is just a wild guess as to what may be needed in the future. With OO it's much more dynamic, in that the invoked class creates the storage, rather than the invoking program, so there is (I believe!) no need for silly things like filler in anticipation of future needs. Now I didn't write the TXND routine, but I imagine that if I were to rewrite it I might do something like this... ***BEGIN TXNDLINK COPYBOOK*** 01 TXND-PASSED-DATA. 05 TXND-PASSED-DATA-LEN COMP PIC S9(4). 05 TXND-CALLER-ID PIC X(8). 05 TXND-CURRENT-SUBROUTINE PIC X(12). 05 TXND-COMPRESS-LINE-SW PIC X. 88 TXND-COMPRESS-LINES VALUE 'Y'. 05 TXND-1LOC-DESC-SW PIC X. 88 1LOC-DESC-WANTED VALUE 'Y'. 05 TXND-MSTR-SEGMENT PIC X(1500). 05 TXND-TRAN-SEGMENT PIC X(50). 05 TXND-DESC-SEGMENT PIC X(55). 01 TXND-RETURNED-DATA. 05 TXND-RETURNED-DATA-LEN COMP PIC S9(4). 05 TXND-SHORT-DESC PIC X(10). 05 TXND-LONG-DESC-1 PIC X(75). 05 TXND-LONG-DESC-2 PIC X(75). 05 TXND-LONG-DESC-3 PIC X(75). 05 TXND-SHORT-DESC-NUM PIC 9(9). 05 TXND-CONVERTED-CHECK-SW PIC X. 88 TXND-CONVERTED-CHECK VALUE 'Y'. 05 TXND-ICM-TRAN-TYPE PIC X(10). ***END TXNDCOPYBOOK*** --------------------------------------- WORKING-STORAGE SECTION. COPY TXNDLINK. PROCEDURE DIVISION. MOVE LENGTH OF TXND-PASSED-DATA TO TXND-PASSED-DATA-LEN MOVE LENGTH OF TXND-RETURNED-DATA TO TXND-RETURNED-DATA-LEN CALL TXND-SUBROUTINE USING TXND-PASSED-DATA TXND-RETURNED-DATA TXND itself would look something like this: PROGRAM-ID. TXND. WORKING-STORAGE SECTION. COPY TXNDLINK. LINKAGE SECTION. 01 PASSED-DATA. 05 PASSED-DATA-LEN COMP PIC S9(4). 05 PASSED-DATA-AREA. 10 PIC X OCCURS 1 TO 9999 DEPENDING ON PASSED-DATA-LEN. 01 RETURNED-DATA. 05 RETURNED-DATA-LEN COMP PIC S9(4). 05 RETURNED-DATA-AREA. 10 PIC X OCCURS 1 TO 9999 DEPENDING ON RETURNED-DATA-LEN. PROCEDURE DIVISION USING PASSED-DATA, RETURNED-DATA. MOVE PASSED-DATA TO TXND-PASSED-DATA MOVE RETURNED-DATA TO TXND-RETURNED-DATA PERFORM MAINLINE MOVE TXND-PASSED-DATA TO PASSED-DATA MOVE TXND-RETURNED-DATA TO RETURNED-DATA EXIT PROGRAM. MAINLINE. * DO STUFF HERE USING TXND-PASSED-DATA AND SETTING TXND-RETURNED-DATA END PROGRAM TXND. I don't like the need for the calling program to set those length fields, but I guess that's a minor complaint. If my COBOL supported the ANY LENGTH phrase I think that would eliminate the need for the LEN fields altogether, since (I guess) COBOL would implicitly pass the length values. That would be very nice! Of course even this method is not without it's problems. If a field, particularly a numeric field, is added to the PASSED-DATA area you would have to make sure to check that field for valid values prior to utilizing it, otherwise assume some sort of default. And then imagine that we want to change the three "LONG-DESC" fields from 75 bytes to 100. Well, now we're recompiling everything again! Or adding new fields to the end. More than anything, this kind of thing gives me a desire for "object oriented programming". The fields in TXND-PASSED-DATA would be input properties and the fields in TXND-RETURNED-DATA would be output properties. Anyway, if anyone can see anything wrong with my thoughts about how to 'fix' my TXND routine without the use of OO COBOL I'd be interested, as I may well make these changes at some point. Or at least to something similar for future subroutines we might develop. Another thing that would be nice is if COBOL had a way of counting the number of parameters passed to it. Actually, I think the OPTIONAL and OMITTED, were they availible in my COBOL, would work. Something like the following: PROGRAM-ID. MY-SUBR. PROCEDURE DIVISION USING REQUIRED-FIELD1, REQUIRED-FIELD2, OPTIONAL OPTIONAL-FIELD1, OPTIONAL OPTIONAL-FIELD2. IF OPTIONAL-FIELD-1 NOT OMITTED MOVE SOMETHING TO OPTIONAL-FIELD1 END-IF ---- * IN CALLING PROGRAM... CALL 'MY-SUBR' USING FIELD1, FIELD2 CALL 'MY-SUBR' USING FIELD1, FIELD2, FIELD3 CALL 'MY-SUBR' USING FIELD1, FIELD2, OMITTED, FIELD4 But given that this is *not* available, other than passing a field containing the number of fields passed, is there anything I can do? Frank --- Frank Swarbrick Senior Developer/Analyst - Mainframe Applications FirstBank Data Corporation - Lakewood, CO USA
Post Follow-up to this messagePowered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.