SOM Language Neutrality: An OO COBOL Perspective: Difference between revisions
No edit summary |
|||
(8 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
by [[Robert A. Pittman, Jr.]] | {{IBM-Reprint}} | ||
''by [[Robert A. Pittman, Jr.]]'' | |||
Information: ([https://web.archive.org/web/19980120023047/http://pscc.dfw.ibm.com:80/psmag/Mar96/pittcode.txt pittcode.txt]) | Information: ([https://web.archive.org/web/19980120023047/http://pscc.dfw.ibm.com:80/psmag/Mar96/pittcode.txt pittcode.txt]) | ||
''This article describes an object-oriented COBOL program using SOM-enabled classes written in C++. It illustrates the language neutrality of SOMobjects and introduces many of COBOL's new object-oriented language extensions.'' | |||
written in C++. It illustrates the language neutrality of SOMobjects and introduces | |||
many of COBOL's new object-oriented language extensions.'' | |||
The introduction of object-oriented (OO) language extensions to the syntax of the | The introduction of object-oriented (OO) language extensions to the syntax of the COBOL programming language is an exciting development in object-oriented programming and design. With object-oriented COBOL, enterprises can adopt a phased approach to object technology and migrate to this new technology in a staged, orderly fashion. | ||
COBOL programming language is an exciting development in object-oriented | |||
programming and design. With object-oriented COBOL, enterprises can adopt a phased | |||
approach to object technology and migrate to this new technology in a staged, orderly | |||
fashion. | |||
Programmers with a sound foundation in COBOL can write object-oriented programs | Programmers with a sound foundation in COBOL can write object-oriented programs with minimal training. Indeed, the greatest obstacle programmers face is not learning new verbs and data types, but acquiring an OO mindset. | ||
with minimal training. Indeed, the greatest obstacle programmers face is not learning new | |||
verbs and data types, but acquiring an OO mindset. | |||
In the new IBM family of COBOL products, syntax is compatible across workstation, | In the new IBM family of COBOL products, syntax is compatible across workstation, midrange, and host platforms. SOMobjects are also portable across these platforms, meaning that you can develop a COBOL program using SOM on a workstation and port it unchanged to a host or midrange environment. | ||
midrange, and host platforms. SOMobjects are also portable across these platforms, | |||
meaning that you can develop a COBOL program using SOM on a workstation and port | |||
it unchanged to a host or midrange environment. | |||
SOM also adds the benefit of language independence; a SOM-enabled class can be developed in SOM's IDL (interface definition language), C++, Smalltalk, or COBOL. | SOM also adds the benefit of language independence; a SOM-enabled class can be developed in SOM's IDL (interface definition language), C++, Smalltalk, or COBOL. And, SOM-enabled classes can be used by programs coded in different languages. This assertion provides the basis for the program in this article. | ||
== OO COBOL Background == | == OO COBOL Background == | ||
The language extensions introduced in IBM's family of COBOL products are based upon | The language extensions introduced in IBM's family of COBOL products are based upon the proposed ANSI 1997 standards. Although a number of issues regarding these proposed standards (such as object persistence and exception) have yet to be resolved, there is a consensus about the proposed OO language extensions. This consensus is the basis of the new genre of object-oriented COBOL compilers introduced by IBM and others. As more of the proposed standards achieve consensus, compiler vendors will incorporate these standards into their products. | ||
the proposed ANSI 1997 standards. Although a number of issues regarding these | |||
proposed standards (such as object persistence and exception) have yet to be resolved, | |||
there is a consensus about the proposed OO language extensions. This consensus is the | |||
basis of the new genre of object-oriented COBOL compilers introduced by IBM and | |||
others. As more of the proposed standards achieve consensus, compiler vendors will | |||
incorporate these standards into their products. | |||
== SOM and the IBM COBOL Family == | == SOM and the IBM COBOL Family == | ||
IBM supports the Object Management Group's Common Object Request Broker | IBM supports the Object Management Group's Common Object Request Broker Architecture (CORBA) for object interoperability. Backing up that support is IBM's SOM, an implementation of CORBA making objects portable across development languages. Both the OS/2 and MVS COBOL compilers feature Direct-to-SOM technology, so you can create language-neutral objects without extensive object-oriented programming experience. | ||
Architecture (CORBA) for object interoperability. Backing up that support is IBM's | |||
SOM, an implementation of CORBA making objects portable across development | |||
languages. Both the OS/2 and MVS COBOL compilers feature Direct-to-SOM | |||
technology, so you can create language-neutral objects without extensive object-oriented | |||
programming experience. | |||
By utilizing a compiler option, you can generate SOM IDL directly from a class | By utilizing a compiler option, you can generate SOM IDL directly from a class definition coded in COBOL. You can then compile this IDL using the SOM compiler, which places it into a SOM interface repository (IR). This process is easy and requires no knowledge of IDL coding. | ||
definition coded in COBOL. You can then compile this IDL using the SOM compiler, | |||
which places it into a SOM interface repository (IR). This process is easy and requires no | |||
knowledge of IDL coding. | |||
== Development Environment == | == Development Environment == | ||
The COBOL code in this article was written using VisualAge for COBOL for OS/2 with | The COBOL code in this article was written using VisualAge for COBOL for OS/2 with the latest Corrective Service Diskette (CSD) installed on a system running OS/2 Warp. | ||
the latest Corrective Service Diskette (CSD) installed on a system running OS/2 Warp. | VisualAge for COBOL for OS/2 includes excellent visual programming tools, an interactive debugger, and advanced data utility functions. It also uses the WorkFrame program management tool. | ||
VisualAge for COBOL for OS/2 includes excellent visual programming tools, an | |||
interactive debugger, and advanced data utility functions. It also uses the WorkFrame | |||
program management tool. | |||
Relevant compiler options used were TYPECHK, which performs typechecking of | Relevant compiler options used were TYPECHK, which performs typechecking of parameters against method interfaces, and PGMNAME(MIXED) which allows the use of mixed-case program, class, and method names. | ||
parameters against method interfaces, and PGMNAME(MIXED) which allows the use of | |||
mixed-case program, class, and method names. | |||
The development machine was a personal computer with a 90 MHz Intel Pentium | The development machine was a personal computer with a 90 MHz Intel Pentium processor and 32 MB of RAM. For a full installation, VisualAge for COBOL for OS/2 requires 170 MB of disk space, a 486-class processor, and 24 MB of RAM. | ||
processor and 32 MB of RAM. For a full installation, VisualAge for COBOL for OS/2 | |||
requires 170 MB of disk space, a 486-class processor, and 24 MB of RAM. | |||
== Class Overview == | == Class Overview == | ||
The sample program in this article uses the valet parking application (see Rick Weaver's | The sample program in this article uses the valet parking application (see Rick Weaver's | ||
"IBM System Object | "[[IBM System Object Model—The Wave of the Future (and Now!)]]" article earlier in this issue). This application consists of Valet, Ticket, and Car classes. Other classes (Garage and TktBookS) are used "under the covers" by the aforementioned classes. | ||
issue). This application consists of Valet, Ticket, and Car classes. Other classes (Garage | |||
and TktBookS) are used "under the covers" by the aforementioned classes. | |||
;Note: This article's figures show just the specific lines of code being discussed. Here is the complete program. | |||
== Application Summary == | == Application Summary == | ||
As described in Weaver's article, this application reads an input file that instructs the | As described in Weaver's article, this application reads an input file that instructs the program to either retrieve a car from the garage or park a car in it. | ||
program to either retrieve a car from the garage or park a car in it. | |||
To park a car, you instantiate a car object and set its attributes to those specified on the | To park a car, you instantiate a car object and set its attributes to those specified on the input record. Next, pass the car object to the parkCar method of the valet object, which returns a ticket object. You can query this ticket object to determine in which slot the car was parked, then display an appropriate message to the system user. | ||
input record. Next, pass the car object to the parkCar method of the valet object, which | |||
returns a ticket object. You can query this ticket object to determine in which slot the car | |||
was parked, then display an appropriate message to the system user. | |||
To retrieve a car, you create a ticket object and set its slot number attribute to the value | To retrieve a car, you create a ticket object and set its slot number attribute to the value on the input record. Next, invoke the retrieveCar method of the valet object, passing it the ticket object just created. The retrieveCar method returns a car object (or an invalid object if there is no car in the slot). Then obtain the attributes of the returned car object and write a message to the system user. | ||
on the input record. Next, invoke the retrieveCar method of the valet object, passing | |||
it the ticket object just created. The retrieveCar method returns a car object (or an | |||
invalid object if there is no car in the slot). Then obtain the attributes of the returned car | |||
object and write a message to the system user. | |||
== Implementing in OO COBOL == | == Implementing in OO COBOL == | ||
Readers familiar with traditional COBOL programming should notice some differences | Readers familiar with traditional COBOL programming should notice some differences in the code presented in this article. These differences arise due to the proposed ANSI 1997 standards on object-oriented extensions to the COBOL language. | ||
in the code presented in this article. These differences arise due to the proposed ANSI | |||
1997 standards on object-oriented extensions to the COBOL language. | |||
One of the first things you will code in this exercise is the configuration section | One of the first things you will code in this exercise is the configuration section repository. The repository, shown in Figure 1, identifies the classes that the program will | ||
repository. The repository, shown in Figure 1, identifies the classes that the program will | |||
need from the interface repository. The client program includes the Car, Ticket, and Valet | need from the interface repository. The client program includes the Car, Ticket, and Valet | ||
classes. The subject of a class statement indicates the name of the class as it will be | classes. The subject of a class statement indicates the name of the class as it will be | ||
referenced within the program. For example, the Car class in the repository will be | referenced within the program. For example, the Car class in the repository will be | ||
referenced as Car in the program. | referenced as Car in the program. | ||
<pre> | |||
REPOSITORY. | |||
<pre>REPOSITORY. | |||
CLASS Car IS "Car" | CLASS Car IS "Car" | ||
CLASS Ticket IS "Ticket" | CLASS Ticket IS "Ticket" | ||
Line 106: | Line 59: | ||
</pre> | </pre> | ||
'''Figure 1. Configuration Section Repository''' | '''Figure 1. Configuration Section Repository''' | ||
In the program's working-storage section, object references (a data type introduced in the | In the program's working-storage section, object references (a data type introduced in the | ||
Line 114: | Line 66: | ||
Figure 2 lists the object handles defined in the working-storage section. Notice how they | Figure 2 lists the object handles defined in the working-storage section. Notice how they | ||
relate to the classes defined in the repository. | relate to the classes defined in the repository. | ||
<pre> | <pre> | ||
********************************** | ********************************** | ||
Line 126: | Line 75: | ||
01 valetObj USAGE OBJECT REFERENCE Valet. | 01 valetObj USAGE OBJECT REFERENCE Valet. | ||
</pre> | </pre> | ||
'''Figure 2. Object Handles''' | '''Figure 2. Object Handles''' | ||
Notice in Figure 3 that pointers are coded for each text attribute within the objects. These | Notice in Figure 3 that pointers are coded for each text attribute within the objects. These | ||
are needed to satisfy typechecking at compilation, when the parameters passed to | are needed to satisfy typechecking at compilation, when the parameters passed to methods are verified to be compatible with the methods' interfaces. | ||
methods are verified to be compatible with the methods' interfaces. | |||
The valet, ticket, and car objects' attributes are strings. To set one of these attributes, the | The valet, ticket, and car objects' attributes are strings. To set one of these attributes, the attribute's value is modified in working-storage and the appropriate pointer's values are | ||
attribute's value is modified in working-storage and the appropriate pointer's values are | set to the attribute's address. The pointer is then passed as a parameter to the _set method. When retrieving an attribute value, the _get method returns a pointer, the handling of which will be discussed later. | ||
set to the attribute's address. The pointer is then passed as a parameter to the _set | |||
method. When retrieving an attribute value, the _get method returns a pointer, the | |||
handling of which will be discussed later. | |||
Figure 3 represents a definition of a string attribute in the working-storage section, with | Figure 3 represents a definition of a string attribute in the working-storage section, with | ||
the associated pointer for the string. COMP-5 denotes a binary data item, in this case a | the associated pointer for the string. COMP-5 denotes a binary data item, in this case a | ||
halfword in length, and indicates that the native binary format of the environment | halfword in length, and indicates that the native binary format of the environment platform is to represent internal data. Alternately, COMP means that the little-endian format is applied in the PC architecture, while the big-endian format is used on the AIX and MVS platforms. | ||
platform is to represent internal data. Alternately, COMP means that the little-endian | |||
format is applied in the PC architecture, while the big-endian format is used on the AIX | |||
and MVS platforms. | |||
<pre> | <pre> | ||
***************************************************** | ***************************************************** | ||
Line 153: | Line 92: | ||
01 WS-VN-POINTER USAGE POINTER. | 01 WS-VN-POINTER USAGE POINTER. | ||
01 WS-VALET-NAME. | 01 WS-VALET-NAME. | ||
05 WS-VN-LL | 05 WS-VN-LL PIC S9(4) COMP-5. | ||
05 WS-VN-NAME PIC X(40). | 05 WS-VN-NAME PIC X(40). | ||
</pre> | </pre> | ||
'''Figure 3. Work Areas for Valet Object's Attributes''' | '''Figure 3. Work Areas for Valet Object's Attributes''' | ||
In the procedure division in Figure 4, a call is made to somGetGlobalEnvironment, | In the procedure division in Figure 4, a call is made to somGetGlobalEnvironment, which returns a pointer to SOM's global environment variable. This pointer must be passed to the methods of the objects used, except when instantiating or destroying an object. | ||
which returns a pointer to SOM's global environment variable. This pointer must be | |||
passed to the methods of the objects used, except when instantiating or destroying an | |||
object. | |||
<pre> | <pre> | ||
*********************************************************** | *********************************************************** | ||
* SOM global environment variable. | * SOM global environment variable. * | ||
*********************************************************** | *********************************************************** | ||
01 WS-ev USAGE POINTER. | 01 WS-ev USAGE POINTER. | ||
Line 174: | Line 107: | ||
. | . | ||
*********************************************************** | *********************************************************** | ||
* Obtain pointer to SOM's global environment variable. * | * Obtain pointer to SOM's global environment variable. * | ||
*********************************************************** | *********************************************************** | ||
CALL "somGetGlobalEnvironment" RETURNING WS-ev. | CALL "somGetGlobalEnvironment" RETURNING WS-ev. | ||
</pre> | </pre> | ||
'''Figure 4. SOM Global Environment Variable''' | '''Figure 4. SOM Global Environment Variable''' | ||
To create an object, invoke the somNew method (a new verb | To create an object, invoke the somNew method (a new verb - introduced in the 1997 ANSI standard - which is inherited from SOMobject) on the class name of the object specified | ||
ANSI standard | |||
in the repository. This method returns the object handle and allocates memory for it. | in the repository. This method returns the object handle and allocates memory for it. | ||
In Figure 5, note the use of somNew on the Valet class, which returns a valet object. | In Figure 5, note the use of somNew on the Valet class, which returns a valet object. Refer to the repository (Figure 1) and the object reference (Figure 2) in the working-storage section, and observe their relationships. Subsequently, when you invoke the object, you invoke methods on its handle and not its class name. | ||
Refer to the repository (Figure 1) and the object reference (Figure 2) in the working- | |||
storage section, and observe their relationships. Subsequently, when you invoke the | |||
object, you invoke methods on its handle and not its class name. | |||
<pre> | <pre> | ||
*********************************************************** | *********************************************************** | ||
* Create a valet object. | * Create a valet object. * | ||
*********************************************************** | *********************************************************** | ||
INVOKE Valet "somNew" RETURNING valetObj. | INVOKE Valet "somNew" RETURNING valetObj. | ||
</pre> | </pre> | ||
'''Figure 5. Creating an Object''' | '''Figure 5. Creating an Object''' | ||
Notice in Figure 6 that you pass the pointer to the global environment variable as the first | Notice in Figure 6 that you pass the pointer to the global environment variable as the first | ||
parameter when invoking methods on the objects. This parameter, as well as all others | parameter when invoking methods on the objects. This parameter, as well as all others used for this exercise, is passed "by value" rather than "by reference" (the default). ''By value'' eliminates a level of indirection and is expected by the classes you are using, whereas ''by reference'' passes a pointer to the parameter, which is typically used in COBOL programming. | ||
used for this exercise, is passed "by value" rather than "by reference" (the default). ''By | |||
value'' eliminates a level of indirection and is expected by the classes you are using, | |||
whereas ''by reference'' passes a pointer to the parameter, which is typically used in | |||
COBOL programming. | |||
For compatibility, string attributes are null-terminated by moving a low-value (binary | For compatibility, string attributes are null-terminated by moving a low-value (binary zero, X"00") to the position immediately following the last character. Figure 6 sets the valet object's name attribute. The prefix Z before the literal indicates that it will be null- | ||
zero, X"00") to the position immediately following the last character. Figure 6 sets the | |||
valet object's name attribute. The prefix Z before the literal indicates that it will be null- | |||
terminated. Figure 6 also sets up a pointer to the attribute's address, to be passed to the | terminated. Figure 6 also sets up a pointer to the attribute's address, to be passed to the | ||
method. The object's handle is invoked, rather than the class name, which was invoked | method. The object's handle is invoked, rather than the class name, which was invoked during object creation. | ||
during object creation. | |||
<pre> | <pre> | ||
*********************************************************** | *********************************************************** | ||
* Initialize fields and work areas. Valet name is | * Initialize fields and work areas. Valet name is * | ||
* padded with low values for C++'s null character for | * padded with low values for C++'s null character for * | ||
* string termination. | * string termination. * | ||
*********************************************************** | *********************************************************** | ||
MOVE Z"Fritz von Hochsmeier" TO WS-VN-NAME. | MOVE Z"Fritz von Hochsmeier" TO WS-VN-NAME. | ||
Line 222: | Line 141: | ||
SET WS-VN-POINTER TO ADDRESS OF WS-VN-NAME. | SET WS-VN-POINTER TO ADDRESS OF WS-VN-NAME. | ||
*********************************************************** | *********************************************************** | ||
* Set the valet object's name attribute, pass a | * Set the valet object's name attribute, pass a * | ||
* pointer to the name work area. * | * pointer to the name work area. * | ||
*********************************************************** | *********************************************************** | ||
INVOKE valetObj "_set_valetName" | INVOKE valetObj "_set_valetName" | ||
USING BY VALUE WS-ev | |||
WS-VN-POINTER. | |||
</pre> | </pre> | ||
'''Figure 6. Valet Object's Name Attribute''' | '''Figure 6. Valet Object's Name Attribute''' | ||
It may seem odd to set up a linkage section in a program that is executed directly and | Because the _get methods return pointers to the attributes they are getting, and because COBOL does not not allow altering the address of an item defined in working-storage, I coded a variable in the linkage section that is used as a work area. The address of this variable is set to the pointer value returned by the _get method. The contents are then copied to the attribute defined in working-storage, and the length up to the null-termination character is determined. For simplicity's sake, I arbitrarily assigned a length of 100 bytes to the variable, allowing me to use it for all string attributes referenced in the program. | ||
never called, but it is necessary to obtain the values of the objects' string attributes. | |||
It may seem odd to set up a linkage section in a program that is executed directly and never called, but it is necessary to obtain the values of the objects' string attributes. | |||
Figure 7 gives the working-storage definition of the car object's color attribute. Figure 8 | Figure 7 gives the working-storage definition of the car object's color attribute. Figure 8 | ||
shows the generic work field to be used to obtain the value of a string attribute. Figure 9 | shows the generic work field to be used to obtain the value of a string attribute. Figure 9 | ||
determines the car object's color attribute. Notice how a pointer is returned. | determines the car object's color attribute. Notice how a pointer is returned. | ||
<pre> | <pre> | ||
*********************************************************** | *********************************************************** | ||
* Work areas for car object's color attribute. | * Work areas for car object's color attribute. * | ||
*********************************************************** | *********************************************************** | ||
01 WS-CC-POINTER USAGE POINTER. | 01 WS-CC-POINTER USAGE POINTER. | ||
01 WS-CAR-COLOR. | 01 WS-CAR-COLOR. | ||
05 WS-CC-LL | 05 WS-CC-LL PIC 9(4) COMP-5. | ||
05 WS-COLOR | 05 WS-COLOR PIC X(20). | ||
05 WS-COLOR-R REDEFINES WS-COLOR. | 05 WS-COLOR-R REDEFINES WS-COLOR. | ||
10 WS-CCR-BYTE PIC X | |||
OCCURS 20 | |||
INDEXED BY WS-CCR-INDEX. | |||
</pre> | </pre> | ||
'''Figure 7. Car Object's Color Attribute''' | '''Figure 7. Car Object's Color Attribute''' | ||
<PRE> | <PRE> | ||
LINKAGE SECTION. | LINKAGE SECTION. | ||
************************************ | ************************************ | ||
* | * Define a general work area. * | ||
************************************ | ************************************ | ||
01 LS-WORK-AREA PIC X(100). | 01 LS-WORK-AREA PIC X(100). | ||
</PRE> | </PRE> | ||
'''Figure 8. Obtaining the Value of a String Attribute''' | |||
<PRE> | <PRE> | ||
*********************************************** | *********************************************** | ||
Line 277: | Line 185: | ||
*********************************************** | *********************************************** | ||
INVOKE carObj "_get_color" | INVOKE carObj "_get_color" | ||
USING BY VALUE WS-ev | |||
RETURNING WS-CC-POINTER | |||
PERFORM GET-COLOR | PERFORM GET-COLOR | ||
</PRE> | </PRE> | ||
'''Figure 9. Obtaining the Car's Color Attribute''' | '''Figure 9. Obtaining the Car's Color Attribute''' | ||
The code in Figure 10 uses the returned pointer to address the variable defined in the program's linkage section and copies the attribute to the working-storage variable. The length of the attribute up to its null-termination character is also found. | |||
<PRE> | <PRE> | ||
GET-COLOR. | GET-COLOR. | ||
************************************************************ | ************************************************************ | ||
* Gets the color work area from the value pointed to by * | * Gets the color work area from the value pointed to by * | ||
* the pointer returned by the car object's get color * | * the pointer returned by the car object's get color * | ||
* method. | * method. * | ||
************************************************************ | ************************************************************ | ||
SET ADDRESS OF LS-WORK-AREA TO WS-CC-POINTER. | SET ADDRESS OF LS-WORK-AREA TO WS-CC-POINTER. | ||
Line 299: | Line 203: | ||
PERFORM VARYING WS-CCR-INDEX | PERFORM VARYING WS-CCR-INDEX | ||
FROM 1 BY 1 | FROM 1 BY 1 | ||
UNTIL WS-CCR-BYTE (WS-CCR-INDEX) | UNTIL WS-CCR-BYTE (WS-CCR-INDEX) < SPACE | ||
OR WS-CCR-INDEX | OR WS-CCR-INDEX > 20 | ||
SET WS-CC-LL TO WS-CCR-INDEX | SET WS-CC-LL TO WS-CCR-INDEX | ||
END-PERFORM. | END-PERFORM. | ||
</PRE> | </PRE> | ||
'''Figure 10. Getting the Color Work Area''' | '''Figure 10. Getting the Color Work Area''' | ||
General agreement on exception handling has not yet been reached in the proposed ANSI 1997 standards, so the C++ techniques of "throwing" and "catching" exceptions can not | General agreement on exception handling has not yet been reached in the proposed ANSI 1997 standards, so the C++ techniques of "throwing" and "catching" exceptions can not be emulated. To verify that a valid car object was returned by the valet object's retrieveCar method, you call somIsObj, passing the handle of the car object. | ||
be emulated. To verify that a valid car object was returned by the valet object's | |||
retrieveCar method, you call somIsObj, passing the handle of the car object. | |||
somIsObj returns a flag indicating whether the object is valid or invalid. | somIsObj returns a flag indicating whether the object is valid or invalid. | ||
In Figure 11, somIsObj is called to see if an object returned by another method is valid. | In Figure 11, somIsObj is called to see if an object returned by another method is valid. | ||
ValidFlag is subsequently tested to determine the outcome of the call to somIsObj. | ValidFlag is subsequently tested to determine the outcome of the call to somIsObj. | ||
<PRE> | <PRE> | ||
****************************************** | ****************************************** | ||
* See if a car was returned. | * See if a car was returned. * | ||
****************************************** | ****************************************** | ||
CALL "somIsObj" USING BY VALUE carObj | CALL "somIsObj" USING BY VALUE carObj | ||
RETURNING theValidflag | |||
</PRE> | </PRE> | ||
'''Figure 11. Determining Whether a Car was Returned''' | |||
To destroy an object, use somFree, a method inherited from SOMobject, as shown in Figure 12. It frees the memory allocated to the object, because (as in C++) there is no automatic garbage collection in object-oriented COBOL. somFree is invoked on the object's handle, rather than the class name Valet. | |||
To destroy an object, use somFree, a method inherited from SOMobject, as shown in | |||
Figure 12. It frees the memory allocated to the object, because (as in C++) there is no | |||
automatic garbage collection in object-oriented COBOL. somFree is invoked on the | |||
object's handle, rather than the class name Valet. | |||
<PRE> | <PRE> | ||
*********************************************************** | *********************************************************** | ||
* The valet clocks out and closes the garage. | * The valet clocks out and closes the garage. * | ||
*********************************************************** | *********************************************************** | ||
INVOKE valetObj "somFree". | INVOKE valetObj "somFree". | ||
</PRE> | </PRE> | ||
'''Figure 12. Destroying an Object''' | '''Figure 12. Destroying an Object''' | ||
== Developing the Client Program == | == Developing the Client Program == | ||
To develop the client program with VisualAge for COBOL for OS/2, first create .LIB | To develop the client program with VisualAge for COBOL for OS/2, first create .LIB files for the DLLs supplied for the classes used by executing the following command from an OS/2 command line: | ||
files for the DLLs supplied for the classes used by executing the following command | IMPLIB valet.lib valet.dll | ||
from an OS/2 command line: | Next, open up the VisualAge COBOL Icon View and select the "Create New Project" icon (see Figure 13). | ||
Next, open up the VisualAge COBOL Icon View and select the "Create New Project" | |||
icon (see Figure 13). | |||
[[Image:pitt13.gif]] | [[Image:pitt13.gif]] | ||
'''Figure 13. VisualAge COBOL | '''Figure 13. VisualAge COBOL - Icon View''' | ||
From the "Create New Project" window, select "Create a default COBOL project" with a | From the "Create New Project" window, select "Create a default COBOL project" with a project name of valet and a target name of client.exe. Next, select the "Create New Text File with the COBOL Editor" button on the toolbar and enter the source code for the client program. | ||
project name of valet and a target name of client.exe. Next, select the "Create New | |||
Text File with the COBOL Editor" button on the toolbar and enter the source code for the | |||
client program. | |||
Then copy the VALET.IR file, all the .DLL and .LIB files, and the test file CAR.SCR into the valet project's subdirectory. You need the .LIB files to build the project and the | Then copy the VALET.IR file, all the .DLL and .LIB files, and the test file CAR.SCR into the valet project's subdirectory. You need the .LIB files to build the project and the .DLLs and test file for execution. You also need the VALET.IR file to satisfy class typechecking during compilation. | ||
.DLLs and test file for execution. You also need the VALET.IR file to satisfy class | |||
typechecking during compilation. | |||
Next, open the "Tools Setup" option from the toolbar (Figure 14). From here, select "COBOL Compiler" from the Actions list (Figure 15), which presents a notebook of compiler options (Figure 16). | Next, open the "Tools Setup" option from the toolbar (Figure 14). From here, select "COBOL Compiler" from the Actions list (Figure 15), which presents a notebook of compiler options (Figure 16). | ||
Line 367: | Line 250: | ||
[[Image:pitt14.gif]] | [[Image:pitt14.gif]] | ||
'''Figure 14. Valet | '''Figure 14. Valet - Icon View''' | ||
[[Image:pitt15.gif]] | [[Image:pitt15.gif]] | ||
'''Figure 15. Valet | '''Figure 15. Valet - Tools Setup''' | ||
[[Image:pitt16.gif]] | [[Image:pitt16.gif]] | ||
'''Figure 16. Compiler Options | '''Figure 16. Compiler Options''' | ||
'''In this notebook, select the "Link" tab and enter the names of the TICKET.LIB, VALET.LIB, and CAR.LIB files in the library/object file name(s) entry box. You also need the SOMTK.LIB file; this file is supplied with VisualAge for COBOL for OS/2. Then close the compiler options notebook.''' | |||
'''In the "Tools Setup" menu, select the variables pull-down menu (Figure 17) and add a CARS variable with an associated string of car.scr, the name of the file containing your test data.''' | '''In the "Tools Setup" menu, select the variables pull-down menu (Figure 17) and add a CARS variable with an associated string of car.scr, the name of the file containing your test data.''' | ||
[[Image:pitt17.gif]] | [[Image:pitt17.gif]] | ||
'''Figure 17. Valet | '''Figure 17. Valet - Tools Setup''' | ||
'''After closing "Tools Setup," you build the executable file by selecting one of the "Build" options on the toolbar. When the project is built successfully, execute it by selecting the "Run Target" option on the toolbar (Figure 18).''' | '''After closing "Tools Setup," you build the executable file by selecting one of the "Build" options on the toolbar. When the project is built successfully, execute it by selecting the "Run Target" option on the toolbar (Figure 18).''' | ||
Line 395: | Line 272: | ||
[[Image:pitt18.gif]] | [[Image:pitt18.gif]] | ||
'''Figure 18. Valet | '''Figure 18. Valet - Icon View''' | ||
'''If you want, you can package the project's executables and requisite runtime files by selecting the "package" option in the "Project" pull-down menu. This process creates an installable copy of the project that you can move to a target machine.''' | '''If you want, you can package the project's executables and requisite runtime files by selecting the "package" option in the "Project" pull-down menu. This process creates an installable copy of the project that you can move to a target machine.''' | ||
== An Exciting New Dimension for COBOL == | == An Exciting New Dimension for COBOL == | ||
The code presented in this article (part of a complete OO COBOL client program ([https://web.archive.org/web/19980120023047/http://pscc.dfw.ibm.com:80/psmag/Mar96/pittcode.txt pittcode.txt]) illustrates some of the techniques used in developing a COBOL client program with VisualAge for COBOL for OS/2. In this example, the client program | The code presented in this article (part of a complete OO COBOL client program ([https://web.archive.org/web/19980120023047/http://pscc.dfw.ibm.com:80/psmag/Mar96/pittcode.txt pittcode.txt]) illustrates some of the techniques used in developing a COBOL client program with VisualAge for COBOL for OS/2. In this example, the client program used SOM-enabled classes. I used only minimal VisualAge COBOL functionality. Coding a class definition in object-oriented COBOL is another exercise beyond the scope of the topic at hand. | ||
When comparing this COBOL client program to a functionally identical C++ client program, note that COBOL has maintained its verbosity. A comparable C++ client program was developed for Weaver's article, "IBM System Object | When comparing this COBOL client program to a functionally identical C++ client program, note that COBOL has maintained its verbosity. A comparable C++ client program was developed for Weaver's article, "IBM System Object Model—The Wave of the Future (and Now!)." Although the COBOL source code is verbose, the executable file is not. When dynamically linking the referenced classes as DLLs, the executable file was around 17 KB, with no testing logic. This size is certainly reasonable for the functionality provided. | ||
The introduction of object-oriented extensions to the COBOL language adds an exciting | The introduction of object-oriented extensions to the COBOL language adds an exciting dimension to the world's most widely used programming language. These extensions ensure the survival of its widespread usage, paving its way into the new generation of application development. | ||
dimension to the world's most widely used programming language. These extensions | |||
ensure the survival of its widespread usage, paving its way into the new generation of | |||
application development. | |||
[[Category:SOM Articles]] | [[Category:SOM Articles]] |
Latest revision as of 15:16, 28 September 2022
Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation
Information: (pittcode.txt)
This article describes an object-oriented COBOL program using SOM-enabled classes written in C++. It illustrates the language neutrality of SOMobjects and introduces many of COBOL's new object-oriented language extensions.
The introduction of object-oriented (OO) language extensions to the syntax of the COBOL programming language is an exciting development in object-oriented programming and design. With object-oriented COBOL, enterprises can adopt a phased approach to object technology and migrate to this new technology in a staged, orderly fashion.
Programmers with a sound foundation in COBOL can write object-oriented programs with minimal training. Indeed, the greatest obstacle programmers face is not learning new verbs and data types, but acquiring an OO mindset.
In the new IBM family of COBOL products, syntax is compatible across workstation, midrange, and host platforms. SOMobjects are also portable across these platforms, meaning that you can develop a COBOL program using SOM on a workstation and port it unchanged to a host or midrange environment.
SOM also adds the benefit of language independence; a SOM-enabled class can be developed in SOM's IDL (interface definition language), C++, Smalltalk, or COBOL. And, SOM-enabled classes can be used by programs coded in different languages. This assertion provides the basis for the program in this article.
OO COBOL Background
The language extensions introduced in IBM's family of COBOL products are based upon the proposed ANSI 1997 standards. Although a number of issues regarding these proposed standards (such as object persistence and exception) have yet to be resolved, there is a consensus about the proposed OO language extensions. This consensus is the basis of the new genre of object-oriented COBOL compilers introduced by IBM and others. As more of the proposed standards achieve consensus, compiler vendors will incorporate these standards into their products.
SOM and the IBM COBOL Family
IBM supports the Object Management Group's Common Object Request Broker Architecture (CORBA) for object interoperability. Backing up that support is IBM's SOM, an implementation of CORBA making objects portable across development languages. Both the OS/2 and MVS COBOL compilers feature Direct-to-SOM technology, so you can create language-neutral objects without extensive object-oriented programming experience.
By utilizing a compiler option, you can generate SOM IDL directly from a class definition coded in COBOL. You can then compile this IDL using the SOM compiler, which places it into a SOM interface repository (IR). This process is easy and requires no knowledge of IDL coding.
Development Environment
The COBOL code in this article was written using VisualAge for COBOL for OS/2 with the latest Corrective Service Diskette (CSD) installed on a system running OS/2 Warp. VisualAge for COBOL for OS/2 includes excellent visual programming tools, an interactive debugger, and advanced data utility functions. It also uses the WorkFrame program management tool.
Relevant compiler options used were TYPECHK, which performs typechecking of parameters against method interfaces, and PGMNAME(MIXED) which allows the use of mixed-case program, class, and method names.
The development machine was a personal computer with a 90 MHz Intel Pentium processor and 32 MB of RAM. For a full installation, VisualAge for COBOL for OS/2 requires 170 MB of disk space, a 486-class processor, and 24 MB of RAM.
Class Overview
The sample program in this article uses the valet parking application (see Rick Weaver's "IBM System Object Model—The Wave of the Future (and Now!)" article earlier in this issue). This application consists of Valet, Ticket, and Car classes. Other classes (Garage and TktBookS) are used "under the covers" by the aforementioned classes.
- Note
- This article's figures show just the specific lines of code being discussed. Here is the complete program.
Application Summary
As described in Weaver's article, this application reads an input file that instructs the program to either retrieve a car from the garage or park a car in it.
To park a car, you instantiate a car object and set its attributes to those specified on the input record. Next, pass the car object to the parkCar method of the valet object, which returns a ticket object. You can query this ticket object to determine in which slot the car was parked, then display an appropriate message to the system user.
To retrieve a car, you create a ticket object and set its slot number attribute to the value on the input record. Next, invoke the retrieveCar method of the valet object, passing it the ticket object just created. The retrieveCar method returns a car object (or an invalid object if there is no car in the slot). Then obtain the attributes of the returned car object and write a message to the system user.
Implementing in OO COBOL
Readers familiar with traditional COBOL programming should notice some differences in the code presented in this article. These differences arise due to the proposed ANSI 1997 standards on object-oriented extensions to the COBOL language.
One of the first things you will code in this exercise is the configuration section repository. The repository, shown in Figure 1, identifies the classes that the program will need from the interface repository. The client program includes the Car, Ticket, and Valet classes. The subject of a class statement indicates the name of the class as it will be referenced within the program. For example, the Car class in the repository will be referenced as Car in the program.
REPOSITORY. CLASS Car IS "Car" CLASS Ticket IS "Ticket" CLASS Valet IS "Valet".
Figure 1. Configuration Section Repository
In the program's working-storage section, object references (a data type introduced in the proposed ANSI 1997 standard) specify the objects' handles and the classes they reference. Essentially, object references are pointers to the area of memory that has been allocated to an object.
Figure 2 lists the object handles defined in the working-storage section. Notice how they relate to the classes defined in the repository.
********************************** * Define the object handles. * ********************************** 01 carObj USAGE OBJECT REFERENCE Car. 01 ticketObj USAGE OBJECT REFERENCE Ticket. 01 valetObj USAGE OBJECT REFERENCE Valet.
Figure 2. Object Handles
Notice in Figure 3 that pointers are coded for each text attribute within the objects. These are needed to satisfy typechecking at compilation, when the parameters passed to methods are verified to be compatible with the methods' interfaces.
The valet, ticket, and car objects' attributes are strings. To set one of these attributes, the attribute's value is modified in working-storage and the appropriate pointer's values are set to the attribute's address. The pointer is then passed as a parameter to the _set method. When retrieving an attribute value, the _get method returns a pointer, the handling of which will be discussed later.
Figure 3 represents a definition of a string attribute in the working-storage section, with the associated pointer for the string. COMP-5 denotes a binary data item, in this case a halfword in length, and indicates that the native binary format of the environment platform is to represent internal data. Alternately, COMP means that the little-endian format is applied in the PC architecture, while the big-endian format is used on the AIX and MVS platforms.
***************************************************** * Work areas for the valet object's attributes. * ***************************************************** 01 WS-VN-POINTER USAGE POINTER. 01 WS-VALET-NAME. 05 WS-VN-LL PIC S9(4) COMP-5. 05 WS-VN-NAME PIC X(40).
Figure 3. Work Areas for Valet Object's Attributes
In the procedure division in Figure 4, a call is made to somGetGlobalEnvironment, which returns a pointer to SOM's global environment variable. This pointer must be passed to the methods of the objects used, except when instantiating or destroying an object.
*********************************************************** * SOM global environment variable. * *********************************************************** 01 WS-ev USAGE POINTER. . . . *********************************************************** * Obtain pointer to SOM's global environment variable. * *********************************************************** CALL "somGetGlobalEnvironment" RETURNING WS-ev.
Figure 4. SOM Global Environment Variable
To create an object, invoke the somNew method (a new verb - introduced in the 1997 ANSI standard - which is inherited from SOMobject) on the class name of the object specified in the repository. This method returns the object handle and allocates memory for it.
In Figure 5, note the use of somNew on the Valet class, which returns a valet object. Refer to the repository (Figure 1) and the object reference (Figure 2) in the working-storage section, and observe their relationships. Subsequently, when you invoke the object, you invoke methods on its handle and not its class name.
*********************************************************** * Create a valet object. * *********************************************************** INVOKE Valet "somNew" RETURNING valetObj.
Figure 5. Creating an Object
Notice in Figure 6 that you pass the pointer to the global environment variable as the first parameter when invoking methods on the objects. This parameter, as well as all others used for this exercise, is passed "by value" rather than "by reference" (the default). By value eliminates a level of indirection and is expected by the classes you are using, whereas by reference passes a pointer to the parameter, which is typically used in COBOL programming.
For compatibility, string attributes are null-terminated by moving a low-value (binary zero, X"00") to the position immediately following the last character. Figure 6 sets the valet object's name attribute. The prefix Z before the literal indicates that it will be null- terminated. Figure 6 also sets up a pointer to the attribute's address, to be passed to the method. The object's handle is invoked, rather than the class name, which was invoked during object creation.
*********************************************************** * Initialize fields and work areas. Valet name is * * padded with low values for C++'s null character for * * string termination. * *********************************************************** MOVE Z"Fritz von Hochsmeier" TO WS-VN-NAME. SET WS-VN-POINTER TO ADDRESS OF WS-VN-NAME. *********************************************************** * Set the valet object's name attribute, pass a * * pointer to the name work area. * *********************************************************** INVOKE valetObj "_set_valetName" USING BY VALUE WS-ev WS-VN-POINTER.
Figure 6. Valet Object's Name Attribute
Because the _get methods return pointers to the attributes they are getting, and because COBOL does not not allow altering the address of an item defined in working-storage, I coded a variable in the linkage section that is used as a work area. The address of this variable is set to the pointer value returned by the _get method. The contents are then copied to the attribute defined in working-storage, and the length up to the null-termination character is determined. For simplicity's sake, I arbitrarily assigned a length of 100 bytes to the variable, allowing me to use it for all string attributes referenced in the program.
It may seem odd to set up a linkage section in a program that is executed directly and never called, but it is necessary to obtain the values of the objects' string attributes. Figure 7 gives the working-storage definition of the car object's color attribute. Figure 8 shows the generic work field to be used to obtain the value of a string attribute. Figure 9 determines the car object's color attribute. Notice how a pointer is returned.
*********************************************************** * Work areas for car object's color attribute. * *********************************************************** 01 WS-CC-POINTER USAGE POINTER. 01 WS-CAR-COLOR. 05 WS-CC-LL PIC 9(4) COMP-5. 05 WS-COLOR PIC X(20). 05 WS-COLOR-R REDEFINES WS-COLOR. 10 WS-CCR-BYTE PIC X OCCURS 20 INDEXED BY WS-CCR-INDEX.
Figure 7. Car Object's Color Attribute
LINKAGE SECTION. ************************************ * Define a general work area. * ************************************ 01 LS-WORK-AREA PIC X(100).
Figure 8. Obtaining the Value of a String Attribute
*********************************************** * Get the color attribute of the car. * *********************************************** INVOKE carObj "_get_color" USING BY VALUE WS-ev RETURNING WS-CC-POINTER PERFORM GET-COLOR
Figure 9. Obtaining the Car's Color Attribute
The code in Figure 10 uses the returned pointer to address the variable defined in the program's linkage section and copies the attribute to the working-storage variable. The length of the attribute up to its null-termination character is also found.
GET-COLOR. ************************************************************ * Gets the color work area from the value pointed to by * * the pointer returned by the car object's get color * * method. * ************************************************************ SET ADDRESS OF LS-WORK-AREA TO WS-CC-POINTER. MOVE LS-WORK-AREA TO WS-COLOR. PERFORM VARYING WS-CCR-INDEX FROM 1 BY 1 UNTIL WS-CCR-BYTE (WS-CCR-INDEX) < SPACE OR WS-CCR-INDEX > 20 SET WS-CC-LL TO WS-CCR-INDEX END-PERFORM.
Figure 10. Getting the Color Work Area
General agreement on exception handling has not yet been reached in the proposed ANSI 1997 standards, so the C++ techniques of "throwing" and "catching" exceptions can not be emulated. To verify that a valid car object was returned by the valet object's retrieveCar method, you call somIsObj, passing the handle of the car object. somIsObj returns a flag indicating whether the object is valid or invalid.
In Figure 11, somIsObj is called to see if an object returned by another method is valid. ValidFlag is subsequently tested to determine the outcome of the call to somIsObj.
****************************************** * See if a car was returned. * ****************************************** CALL "somIsObj" USING BY VALUE carObj RETURNING theValidflag
Figure 11. Determining Whether a Car was Returned
To destroy an object, use somFree, a method inherited from SOMobject, as shown in Figure 12. It frees the memory allocated to the object, because (as in C++) there is no automatic garbage collection in object-oriented COBOL. somFree is invoked on the object's handle, rather than the class name Valet.
*********************************************************** * The valet clocks out and closes the garage. * *********************************************************** INVOKE valetObj "somFree".
Figure 12. Destroying an Object
Developing the Client Program
To develop the client program with VisualAge for COBOL for OS/2, first create .LIB files for the DLLs supplied for the classes used by executing the following command from an OS/2 command line:
IMPLIB valet.lib valet.dll
Next, open up the VisualAge COBOL Icon View and select the "Create New Project" icon (see Figure 13).
Figure 13. VisualAge COBOL - Icon View
From the "Create New Project" window, select "Create a default COBOL project" with a project name of valet and a target name of client.exe. Next, select the "Create New Text File with the COBOL Editor" button on the toolbar and enter the source code for the client program.
Then copy the VALET.IR file, all the .DLL and .LIB files, and the test file CAR.SCR into the valet project's subdirectory. You need the .LIB files to build the project and the .DLLs and test file for execution. You also need the VALET.IR file to satisfy class typechecking during compilation.
Next, open the "Tools Setup" option from the toolbar (Figure 14). From here, select "COBOL Compiler" from the Actions list (Figure 15), which presents a notebook of compiler options (Figure 16).
Figure 14. Valet - Icon View
Figure 15. Valet - Tools Setup
Figure 16. Compiler Options
In this notebook, select the "Link" tab and enter the names of the TICKET.LIB, VALET.LIB, and CAR.LIB files in the library/object file name(s) entry box. You also need the SOMTK.LIB file; this file is supplied with VisualAge for COBOL for OS/2. Then close the compiler options notebook.
In the "Tools Setup" menu, select the variables pull-down menu (Figure 17) and add a CARS variable with an associated string of car.scr, the name of the file containing your test data.
Figure 17. Valet - Tools Setup
After closing "Tools Setup," you build the executable file by selecting one of the "Build" options on the toolbar. When the project is built successfully, execute it by selecting the "Run Target" option on the toolbar (Figure 18).
Figure 18. Valet - Icon View
If you want, you can package the project's executables and requisite runtime files by selecting the "package" option in the "Project" pull-down menu. This process creates an installable copy of the project that you can move to a target machine.
An Exciting New Dimension for COBOL
The code presented in this article (part of a complete OO COBOL client program (pittcode.txt) illustrates some of the techniques used in developing a COBOL client program with VisualAge for COBOL for OS/2. In this example, the client program used SOM-enabled classes. I used only minimal VisualAge COBOL functionality. Coding a class definition in object-oriented COBOL is another exercise beyond the scope of the topic at hand.
When comparing this COBOL client program to a functionally identical C++ client program, note that COBOL has maintained its verbosity. A comparable C++ client program was developed for Weaver's article, "IBM System Object Model—The Wave of the Future (and Now!)." Although the COBOL source code is verbose, the executable file is not. When dynamically linking the referenced classes as DLLs, the executable file was around 17 KB, with no testing logic. This size is certainly reasonable for the functionality provided.
The introduction of object-oriented extensions to the COBOL language adds an exciting dimension to the world's most widely used programming language. These extensions ensure the survival of its widespread usage, paving its way into the new generation of application development.