Jump to content

SOM Language Neutrality: An OO COBOL Perspective: Difference between revisions

From EDM2
No edit summary
Ak120 (talk | contribs)
 
(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  
''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.[[1]] And, SOM-enabled classes can be used by programs coded in differ
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.
ent 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 Model--The Wave of the Future [and Now!]" article earlier in this  
"[[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]].
;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           PIC S9(4)  COMP-5.
     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--introduced in the 1997  
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--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 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
USING BY VALUE WS-ev
WS-VN-POINTER.
WS-VN-POINTER.
</pre>
</pre>
'''Figure 6. Valet Object's Name Attribute'''  
'''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  
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     PIC 9(4)    COMP-5.
05  WS-CC-LL     PIC 9(4)    COMP-5.
05  WS-COLOR     PIC X(20).
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
10  WS-CCR-BYTE    PIC X
OCCURS 20
OCCURS 20
INDEXED BY WS-CCR-INDEX.
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. *
*   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'''


'''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
USING BY VALUE    WS-ev
RETURNING         WS-CC-POINTER
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.
----


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) &lt; SPACE
UNTIL WS-CCR-BYTE (WS-CCR-INDEX) < SPACE
OR WS-CCR-INDEX &gt; 20
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
RETURNING theValidflag
</PRE>
</PRE>
'''Figure 11. Determining Whether a Car was Returned'''


'''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).
<br> IMPLIB valet.lib valet.dll  
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--Icon View'''
'''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--Icon View'''
'''Figure 14. Valet - Icon View'''


[[Image:pitt15.gif]]
[[Image:pitt15.gif]]


'''Figure 15. Valet--Tools Setup/B&gt;'''
'''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 Visu
alAge for COBOL for OS/2. Then close the compiler options notebook.'''


'''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--Tools Setup'''
'''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--Icon View'''
'''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 use
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.
d 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.
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

by Robert A. Pittman, Jr.

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.