How to implement methods in COBOL!
In OOCOBOL this, of course, is not a problem!
But what do we do when we don't have OOCOBOL?
Note: Keep in mind that each method can and will use different sets of linkage parameters! And the program will abend when more parameters (more 01 levels) are referenced then the caller has passed.
I came up with the following solutions for defining methods in non-OOCOBOL:
The EVALUATE solution
calling program
called program (classProgram1)
(some) advantages:
Standard COBOL.
Simple call structure with descriptive method name(s).
(some) disadvantages:
A lot of cumulative evaluate statements (1 for every class program).
Maintenance intensive (e.g. when a method is deprecated it should be removed from every evaluate statement concerned. When not done then eventually a lot of deprecated when's are needlessly evaluated).
The GO TO DEPENDING ON solution
calling program
called program (classProgram2)
(some) advantages:
Standard COBOL.
Faster then the evaluate statement.
Fewer code lines needed then the evaluate statement.
Simple call structure, but method name is a number which is not descriptive and can easily be confused. You can solve this by defining an 88-level field but that needs to be coded and maintained.
(some) disadvantages:
Unconditional branch (GO TO).
Two exit points (one for each method and one after errorNoSuchMethodRoutine shared by all methods).
Called and calling program are intimately linked (dependent). You cannot(!) just add, remove or, switch methods in the 'GO TO DEPENDING ON' statement. Because this affects the caller.
The pointer solution
calling program
called program (classProgram3)
(some) advantages:
Standard COBOL (I think???).
Fast and direct.
Fewest code lines needed in called program.
There is no maintenance needed as described for the evaluate or go-to-depending-on statement.
(some) disadvantages:
Pointer logic is seldom used.
You always need an additional step to address working-storage data.
Pointer logic can only be used in the same address space.
All codes are poluted with a lot of pointer referencing/dereferencing logic.
Increased possibility to reference random storage without being detected.
In general, more confusing (though this is a matter of getting used to and experience).
The ENTRY solution
calling program
called program (classProgram4)
(some) advantages:
Fast and direct.
Fewest code lines (compared to the solutions given above).
Visually the cleanest structure (compared to the solutions given above).
Simplest maintenance (compared to the solutions given above). Deprecated method that are not removed are never executed (and do therefore not influence the other methods).
It resembles a method (when compared with OOCOBOL).
(some) disadvantages:
Non standard.
The number of entries is limited (however, this should be a non issue in a well designed system).
My personal preference, given the solutions above, is the 'ENTRY' solution.
In OOCOBOL this, of course, is not a problem!
But what do we do when we don't have OOCOBOL?
Note: Keep in mind that each method can and will use different sets of linkage parameters! And the program will abend when more parameters (more 01 levels) are referenced then the caller has passed.
I came up with the following solutions for defining methods in non-OOCOBOL:
The EVALUATE solution
calling program
Code:
MOVE 'methodC' TO whichMethod
CALL 'classProgram1' USING
whichMethod, workData1, workData6
Code:
LINKAGE SECTION.
01 whichMethod PIC X(30)
88 methodA VALUE 'methodA'.
88 methodB VALUE 'methodB'.
88 ...
88 methodZ VALUE ...
01 linkData1 PIC ...
01 linkData2 PIC ...
01 linkData3 PIC ...
01 ...
01 linkDataN PIC ...
PROCEDURE DIVISION USING
linkData1, LinkData2, .... linkDataN.
EVALUATE whichMethod
,
, WHEN methodA
, CALL nestedMethodA
, USING linkData1, linkData6, linkData2
,
, WHEN methodB
, CALL nestedMethodB
, USING linkData2, linkData5, linkData7
,
, WHEN methodC
, CALL nestedMethodC
, USING linkData1, linkData6
,
, ...
,
, WHEN methodLast
, CALL nestedMethod...
, USING ....
,
, WHEN OTHER
, PERFORM errorNoSuchMethodRoutine
,
END-EVALUATE
GOBACK
.
Standard COBOL.
Simple call structure with descriptive method name(s).
(some) disadvantages:
A lot of cumulative evaluate statements (1 for every class program).
Maintenance intensive (e.g. when a method is deprecated it should be removed from every evaluate statement concerned. When not done then eventually a lot of deprecated when's are needlessly evaluated).
The GO TO DEPENDING ON solution
calling program
Code:
MOVE 3 TO whichMethod
CALL 'classProgram2' USING
whichMethod, workData1, workData6
Code:
LINKAGE SECTION.
01 whichMethod PIC 9(02).
01 linkData1 PIC ...
01 linkData2 PIC ...
01 linkData3 PIC ...
01 ...
01 linkDataN PIC ...
PROCEDURE DIVISION USING
linkData1, LinkData2, .... linkDataN.
GO TO methodA, methodB, methodC, ... , methodN
DEPENDING ON whichMethod.
* fall through is same as EVALUATE WHEN OTHER condition.
PERFORM errorNoSuchMethodRoutine
GOBACK
.
methodA.
CALL nestedMethodA
USING linkData1, linkData6, linkData2
GOBACK
.
methodB.
CALL nestedMethodB
USING linkData2, linkData5, linkData7
GOBACK
.
methodC.
CALL nestedMethodC
USING linkData1, linkData6
GOBACK
.
Standard COBOL.
Faster then the evaluate statement.
Fewer code lines needed then the evaluate statement.
Simple call structure, but method name is a number which is not descriptive and can easily be confused. You can solve this by defining an 88-level field but that needs to be coded and maintained.
(some) disadvantages:
Unconditional branch (GO TO).
Two exit points (one for each method and one after errorNoSuchMethodRoutine shared by all methods).
Called and calling program are intimately linked (dependent). You cannot(!) just add, remove or, switch methods in the 'GO TO DEPENDING ON' statement. Because this affects the caller.
The pointer solution
calling program
Code:
WORKING-STORAGE SECTION.
01 workDate1 PIC ..
01 workData6 PIC ..
01 listOfPointers.
05 data1pointer USAGE POINTER VALUE NULL.
05 data2pointer USAGE POINTER VALUE NULL.
* setPointer sets the pointer in the
* linkage section of the called program
* to the address of the data area (workDataX).
CALL setPointer USING workDate1 data1
CALL setPointer USING workData6 data2
MOVE 'methodC' TO whichMethod
CALL 'classProgram3' USING whichMethod, listOfPointers
Code:
LINKAGE SECTION.
01 whichMethod PIC X(30).
01 pointerList PIC X(01).
PROCEDURE DIVISION USING whichMethod pointerList.
CALL whichMethod USING pointerList
GOBACK
.
ID DIVISION.
PROGRAM-ID. methodC.
* method C knows how many parameters are used!
* dereference the 2 parameters using the pointerList.
...
Standard COBOL (I think???).
Fast and direct.
Fewest code lines needed in called program.
There is no maintenance needed as described for the evaluate or go-to-depending-on statement.
(some) disadvantages:
Pointer logic is seldom used.
You always need an additional step to address working-storage data.
Pointer logic can only be used in the same address space.
All codes are poluted with a lot of pointer referencing/dereferencing logic.
Increased possibility to reference random storage without being detected.
In general, more confusing (though this is a matter of getting used to and experience).
The ENTRY solution
calling program
Code:
CALL 'classProgram4methodC' USING
workData1, workData6.
Code:
LINKAGE SECTION.
01 linkData1 PIC ...
01 linkData2 PIC ...
01 linkData3 PIC ...
01 ...
01 linkData6 PIC ...
01 ...
01 linkDataN PIC ...
PROCEDURE DIVISION.
doNothing-JustReturn.
GOBACK
.
ENTRY 'methodA' USING linkData1, linkData6, linkData2.
CALL nestedMethodA
USING linkData1, linkData6, linkData2.
GOBACK
.
ENTRY 'methodB' USING linkData2, linkData5, linkData7.
CALL nestedMethodB
USING linkData2, linkData5, linkData7.
GOBACK
.
ENTRY 'methodC' USING linkData1, linkData6
CALL nestedMethodC
USING linkData1, linkData6.
GOBACK
.
Fast and direct.
Fewest code lines (compared to the solutions given above).
Visually the cleanest structure (compared to the solutions given above).
Simplest maintenance (compared to the solutions given above). Deprecated method that are not removed are never executed (and do therefore not influence the other methods).
It resembles a method (when compared with OOCOBOL).
(some) disadvantages:
Non standard.
The number of entries is limited (however, this should be a non issue in a well designed system).
My personal preference, given the solutions above, is the 'ENTRY' solution.