Michael Coughlan
Page 66
the instance methods of all the superclasses until it finds a method matching the
message.
If SUPER is used from a factory method, the system searches for a factory method
beginning with the factory object code of the superclass immediately above the
class and searches its way up through the factory methods of all the superclasses
until it finds a method matching the message.
For instance, in Listing 19-1-cls, the new method in the FACTORY needs to invoke the
new method in the base class. This is achieved using the statement
INVOKE SUPER "new" RETURNING TestObject-lnk.
Writing Your Own Classes
When you write an OO application, you need to create your own classes. A class program has the structure shown in Figure 19-5, and the entries required are outlined in the class template in Example 19-5.
532
Chapter 19 ■ OO-COBOL
Figure 19-5. Structure of a class program
Example 19-5. A Class Program Template
CLASS-ID. Template-cls AS "template"
inherits from Base.
* Class identification.
ENVIRONMENT DIVISION.
* Optional but when used all normal ENVIRONMENT DIVISION entries are valid
: : : : : : : : :
CONFIGURATION SECTION.
* Optional entry but the REPOSITORY is part of the CONFIGURATION SECTION
: : : : : : : : :
REPOSITORY.
* The Repository paragraph names the files containing the executables
* for each class.
* The executable for Template-cls is in the file template.
CLASS BASE AS "base"
CLASS Template-cls AS "tester".
FACTORY
* Defines the start of the factory object.
ENVIRONMENT DIVISON.
DATA DIVISION.
533
Chapter 19 ■ OO-COBOL
* Defines factory object data
WORKING-STORAGE SECTION.
* Defines factory object data
: : : : : : : : :
METHOD-ID. new.
* If initialization is required there may be a "new" of factory method.
* This overrides "new" coming from Base.
: : : : : : : : :
END METHOD new.
END FACTORY.
OBJECT.
* Start of the code that defines the behaviour of class instances.
WORKING-STORAGE SECTION.
* Defines instance data visible to all methods of the instance.
: : : : : : : : :
METHOD-ID. ExampleTemplateMethod.
* Start of instance method "ExampleTemplateMethod "
...
END METHOD ExampleTemplateMethod.
END OBJECT.
* End of code for instance objects.
END CLASS Example.
The Issue of Scope
Whenever you write a class program, you have to be aware of the consequences of declaring data items in various parts of the program. When I refer to the scope of a data item, I am referring to its lifetime: how long it persists.
The scoping issues of data items declared in the class program are summarized in Table 19-3, and Listing 19-2
demonstrates these issues in an example program.
Table 19-3. Class Program Scoping Issues
Where Declared
Scope
WORKING-STORAGE SECTION of the FACTORY
A data item declared in the WORKING-STORAGE SECTION of the
FACTORY is visible only to factory methods; and because there is only
one factory object, there is only one instance of the data item. The
item persists as long as the class program is alive.
WORKING-STORAGE SECTION of the OBJECT
A data item declared in the WORKING-STORAGE SECTION of the OBJECT
is visible only to object instance methods. There is an instance of the
data item for each object, and the data item will persist as long as the
instance is alive (has not been finalized).
LOCAL-STORAGE SECTION of any method
A data item declared in the LOCAL-STORAGE SECTION of any method
(factory of instance object) visible only to the method, and it persists
only as long has the method is alive.
534
Chapter 19 ■ OO-COBOL
Listing 19-2. Example Program to Demonstrate Scoping Issues
IDENTIFICATION DIVISION.
PROGRAM-ID. Listing19-2.
* AUTHOR. Michael Coughlan.
* Demonstrates the difference between Factory methods & data
* and instance methods & data.
* It is also used to demonstrate the scope of
* data items declared in different parts of the program.
REPOSITORY.
CLASS Tester-cls AS "tester".
DATA DIVISION.
WORKING-STORAGE SECTION.
01 Test1-obj OBJECT REFERENCE Tester-cls.
01 Test2-obj OBJECT REFERENCE Tester-cls.
01 Test3-obj OBJECT REFERENCE Tester-cls.
PROCEDURE DIVISION.
Begin.
INVOKE Tester-cls "new" RETURNING Test1-obj
INVOKE Tester-cls "new" RETURNING Test2-obj
INVOKE Tester-cls "new" RETURNING Test3-obj
DISPLAY SPACES
DISPLAY "--------- Test3-obj ViewData -----------"
INVOKE Test3-obj "ViewData"
DISPLAY SPACES
DISPLAY "--------- Test1-obj ViewData -----------"
INVOKE Test1-obj "ViewData"
DISPLAY SPACES
DISPLAY "--------- Test3-obj ViewData again -----"
INVOKE Test3-obj "ViewData"
DISPLAY SPACES
DISPLAY "--------- Test2-obj ViewData -----------"
INVOKE Test2-obj "ViewData" USING BY CONTENT 5
INVOKE Test1-obj "finalize" RETURNING Test1-obj
INVOKE Test2-obj "finalize" RETURNING Test2-obj
INVOKE Test3-obj "finalize" RETURNING Test3-obj
STOP RUN.
535
Chapter 19 ■ OO-COBOL
The program starts by creating three instances of the tester class object. It does this by sending the new message to the class. There is a new method in the class factory, so that method is executed. The purpose of the new method is to demonstrate the difference between data items declared in the WORKING-STORAGE SECTION of the factory and items declared in the LOCAL-STORAGE SECTION of a factory method. The output from the program shows that while the WORKING-STORAGE data items remember their values from invocation to invocation, which allows them to be incremented each time new is invoked, the LOCAL-STORAGE items always show the same value.
There is one other thing going on here under the surface. If you look at the ViewData displays in the Listing 19-2
output, note that the first line displayed shows which instance it is and how many instances there are. In order to display this information, you must note the instance when new is invoked. But although the number of instances can be stored in the factory, the particular instance number cannot. It has to be stored with the particular instance. When you examine the class program, you can see how this is done.
The ViewData displays are also used to show that there are separate data items for each instance. The increment value used to show the difference between data items declared in the WORKING-STORAGE of the OBJECT and those declared in LOCAL-STORAGE of the ViewData method is computed as 10 multiplied by the instance number. That is 10
for instance one, 20 for instance two, and 30 for instance three.
536
Chapter 19 ■ OO-COBOL
The purpose of the ViewData displays is to show that separate instances have been created and that when you invoke an object for the second time, you can see that it has remembered the contents of one variable
but not the other. The class program used by Listing 19-2 is given in Listing 19-2-cls.
Listing 19-2-cls. Class Program Used by Listing 19-2
CLASS-ID. Tester-cls AS "tester"
INHERITS FROM Base.
* AUTHOR. Michael Coughlan.
* Demonstrates the difference between Factory methods and data and Instance methods
* and data. Also demonstrates persistence of data items declared in different areas.
REPOSITORY.
CLASS BASE AS "base"
CLASS Tester-cls AS "tester".
FACTORY.
WORKING-STORAGE SECTION.
*Items declared here are visible only to factory methods and have state memory
01 InstCounter-fws PIC 9 VALUE ZEROS.
01 FactoryData-fws PIC 9 VALUE ZEROS.
METHOD-ID. New.
LOCAL-STORAGE SECTION.
*Items declared here are visible only to this method but do not have state memory.
01 LocalData-mls PIC 9 VALUE ZEROS.
LINKAGE SECTION.
01 TestObject-lnk OBJECT REFERENCE.
PROCEDURE DIVISION RETURNING TestObject-lnk.
Begin.
ADD 2 TO FactoryData-fws LocalData-mls
DISPLAY "Factory Working-Storage data has state memory - "
FactoryData-fws
DISPLAY "but Factory Method Local-Storage data does not - "
LocalData-mls
DISPLAY SPACES
INVOKE SUPER "new" RETURNING TestObject-lnk
ADD 1 TO InstCounter-fws
INVOKE TestObject-lnk "InitialiseData"
USING BY CONTENT InstCounter-fws
EXIT METHOD.
END METHOD New.
METHOD-ID. GetTotalInstCount.
LINKAGE SECTION.
01 TotalInstCount-lnk PIC 9.
PROCEDURE DIVISION RETURNING TotalInstCount-lnk.
Begin.
537
Chapter 19 ■ OO-COBOL
MOVE InstCounter-fws TO TotalInstCount-lnk.
END METHOD GetTotalInstCount.
END FACTORY.
OBJECT.
WORKING-STORAGE SECTION.
*Items declared here are visible only to methods of this
*instance. They are persist for the life of the object instance.
01 ThisInstanceNum-ows PIC 9 VALUE ZEROS.
01 InstObjectData-ows PIC 99 VALUE ZEROS.
METHOD-ID. InitialiseData.
LINKAGE SECTION.
01 InstNumIn-lnk PIC 9.
PROCEDURE DIVISION USING InstNumIn-lnk.
Begin.
MOVE InstNumIn-lnk TO ThisInstanceNum-ows
EXIT METHOD.
END METHOD InitialiseData.
METHOD-ID. ViewData.
LOCAL-STORAGE SECTION.
*Items declared here only exist for the life of the method.
*They do not retain their values between invocations.
01 InstMethodData-mls PIC 99 VALUE ZEROS.
01 TotalInstCount-mls PIC 9 VALUE ZEROS.
01 Increment-mls PIC 99 VALUE ZEROS.
PROCEDURE DIVISION.
Begin.
COMPUTE Increment-mls = 10 * ThisInstanceNum-ows
ADD Increment-mls TO InstObjectData-ows, InstMethodData-mls
INVOKE Tester-cls "GetTotalInstCount"
RETURNING TotalInstCount-mls
DISPLAY "This is instance " ThisInstanceNum-ows
" of " TotalInstCount-mls
DISPLAY "Instance Object Data = " InstObjectData-ows
DISPLAY "Instance Method Data = " InstMethodData-mls
EXIT METHOD.
END METHOD ViewData.
END OBJECT.
END CLASS Tester-cls.
The first thing to note about Listing 19-2-cls is that I have attached a suffix to each data item to assist your understanding. The suffix meanings are as follows:
-ows indicates a data item in the OBJECT WORKING-STORAGE
-mls indicates a data item in the method LOCAL-STORAGE
-lnk indicates a data item in the LINKAGE-SECTION
-fws indicates a data item in the FACTORY WORKING-STORAGE
538
Chapter 19 ■ OO-COBOL
The factory contains a new method. This method overrides the new method in the Base class and its purpose
is to note the number of the particular object instance created and to keep a count of how many instances have been created. There are two data items in the WORKING-STORAGE SECTION of the FACTORY: FactoryData-fws and
InstCounter-fws. FactoryData-fws is used for the purpose of contrast with the LocalData-mls data item declared in the new method. As you can see from the output, FactoryData-fws remembers its value from invocation to
invocation, whereas LocalData-mls starts with a value of ZEROS each time the new method is called. InstCounter-fws holds the count of the number of instances that have been created. Each time new is invoked, this count is incremented.
InstCounter-fws, however, can’t be used to hold the instance number (as soon as the next instance is created, the number is overwritten). Instead, as soon as an instance has been created by the statement
INVOKE SUPER "new" RETURNING TestObject-lnk
the method InitialiseData in the instance just created is invoked and is passed the current value
of InstCounter-fws. InitialiseData then records the number in the instance variable ThisInstanceNum-ows.
Two data items have been declared in the WORKING-STORAGE SECTION of the OBJECT: ThisInstanceNum-ows
and InstObjectData-ows. As I have already mentioned, ThisInstanceNum-ows is used to hold the instance number.
InstObjectData-ows is used to show the contrast between items declared in the WORKING-STORAGE of the OBJECT and items declared in the LOCAL-STORAGE of the method.
One last issue needs some explanation. ViewData can display the instance number because it is stored in the instance data item ThisInstanceNum-ows, but ViewData does not know how many instances have been created. That information is stored in the factory in InstCounter-fws. The problem is that an instance method cannot see a data item declared in the factory. In order to get access to that information the statement
INVOKE Tester-cls "GetTotalInstCount"
RETURNING TotalInstCount-mls
invokes the factory method GetTotalInstCount. This method returns the number of instances as a parameter. Pay particular attention to the target of the INVOKE statement. Instead of targeting the instance object, or SELF, or SUPER, the class name is used (registering the class in the REPOSITORY created the factory object.)
Summary
This chapter introduced OO-COBOL from a particular perspective. The ANS 85 version of COBOL was supposed to bring structured programming to COBOL, but although it had many fine features, it was not entirely successful in this respect. This chapter discussed the shortcomings of the ANS 85 version when attempting to create informational-strength modules and showed how OO-COBOL can be used to fulfill the structured programming promise of ANS 85 COBOL.
You then saw an OO program that implemented the information hiding techniques of an informational-strength module.
Having demonstrated how to create an OO program through an example, I introduced the topic more formally, and you saw the entries required to use a class, invoke a method, and create a class program. The final section discussed the issue of data-item scope and demonstrated the effect of declaring data items in various parts of the class program.
This has been a long journey. I hope that you have enjoyed the trip and have learned something along the way.
Although COBOL has its flaws, its many strengths in the area of its chosen domain account for its dominance in the world of enterprise computing.
539
Chapter 19 ■ OO-COBOL
prOGraMMING eXerCISe
Well, it’s time for the final exercise. If you can locate the stub of your 2B pencil, why not have a go at writing an OO-COBOL program?
/> the Zodiac Signs Compatibility exercise in Chapter 16 required you to write a program that used a contained subprogram called IdentifySign to identify the Zodiac sign for a given birth date. Using the program that you wrote for that exercise as a starting point, write a Zodiac class that supplies the following methods, and then rewrite the Zodiac Sign Compatibility experiment program so that it uses that Zodiac class:
METHOD-ID. "getSignHouse".
LINKAGE SECTION.
01 InDate.
02 InDay PIC XX.
02 InMonth PIC XX.
01 OutZodiacHouse PIC 99.
01 OpStatus PIC 9.
* value of 0 indicates operation was successful
* value of 1 indicates sign is a Cusp Sign
* value of 2 indicates date supplied was invalid
PROCEDURE DIVISION USING InDate, OutZodiacHouse RETURNING OpStatus.
*Accepts a date in form DDMM and returns the Zodiac House value (01-12)
*The twelve houses are Aries, Taurus,Gemini, Cancer, Leo, Virgo,
*Libra, Scorpio, Sagittarius Capricorn, Aquarius, Pisces
*Method should note if the sign is a cusp sign
END METHOD "getSignHouse".
METHOD-ID. "getSignName".
LINKAGE SECTION.
01 INZodiacHouse PIC 99.
01 OutSignName PIC X(11).
01 OpStatus PIC 9.
* value of 0 indicates operation was successful
* value of 1 indicates InZodiacHouse value not in range 01-12
PROCEDURE DIVISION USING InZodiacHouse, OutSignName RETURNING OpStatus.
*Accepts a Zodiac House value and returns the Zodiac Sign name
*For instance house 3 = Gemini
END METHOD "getSignName".
METHOD-ID. "getSignElement".
LINKAGE SECTION.
01 InZodiacHouse PIC 99.
88 ValidSignHouse VALUE 01 THRU 12.
01 OutSignElement PIC X(5).
01 OpStatus PIC 9.
88 InvalidSignHouse VALUE 1.
88 OperationOk VALUE 0.
540
Chapter 19 ■ OO-COBOL
PROCEDURE DIVISION USING InZodiacHouse, OutSignElement RETURNING OpStatus.