|Requirements-based Vocabulary Tutorial||Class Programs|
This chapter describes how you can use objects in your programs. The same rules apply whether the program you write is an Object COBOL class, or a procedural COBOL program in which you want to use Object COBOL objects.
Objects can be used by an application which is not itself object-oriented. This chapter describes how you can add objects to a program and send messages to them. All the information in this chapter applies equally to Object COBOL class programs and to procedural programs which use objects.
This chapter uses examples of code to illustrate points. For the full syntax definitions, see your Language Reference.
Programs which use objects all have certain features in common:
This lists all the classes the program is going to use. If the program itself is an Object COBOL class, the Class-Control paragraph also lists its superclass, and usually the program itself (a class doesn't have to list itself in the Class-Control paragraph if the class-name and filename are the same).
An Object Reference data item holds an object handle. The run-time system assigns a unique object handle to every single object active in your application. An object handle enables you to send messages to the object.
You can also pass object references as parameters when you send a message or make a COBOL CALL, in effect enabling you to pass objects between different parts of an application.
When you send a message to an object, you invoke a method inside the object. A method is a piece of code which performs one of the functions of the object. Some methods receive or return parameters; when you invoke the method you include the parameters as part of the message in the INVOKE statement.
Generally, a program which uses objects will send a message to one or more class objects to create the instance objects it requires. For each instance object created, you must declare an object reference to hold the object handle, although you may overwrite the object handle in an object reference with a new one if you have finished with it. When a program has finished with an object, it should destroy it (by sending it the "finalize" message).
Before you can use an Object COBOL class, you must register it. To do this, you must declare it in the Class-Control paragraph of every program which uses it. This binds the name of the class to the executable file for the class program.
It also makes the name of the class available to your program as an Object Reference data item with the same name as the class. This enables you to send messages to the class object.
The code below shows class registration for classes CharacterArray and myClass:
class-control. CharacterArray is class "chararry" myClass is class "myclass" .
The filename is in quotes after the IS CLASS clause. The spelling and case of a filename in Class-Control must match in all the Class-Control paragraphs which refers to it. You are strongly advised to adopt a convention of specifying all filenames in Class-Control in lower-case. Matching is case-sensitive to keep source-code compatibility between case-insensitive and case-sensitive operating systems.
A data item of type object reference can hold a handle to a class or instance object. In this release of Object COBOL, object references are untyped, so the same data item can hold an object reference for any class or instance object. That is, there is no distinction between the type of object reference declared to hold an instance of one class or another.
You need to declare data items of type OBJECT REFERENCE to hold handles to any objects you will be using.
01 anItem object reference.
You also require object references for any class you are going to use in your program. These are declared automatically when you list your classes in the Class-Control Section.
The only operations you can use on object references are:
To send a message to the object represented by the handle in the object reference. For example:
invoke Object1 "message"
To copy an object reference to a different data item. For example:
set Object1 to Object2
to see whether two object references refer to the same object. For example:
if Object1 = Object2 ...
No other operations are valid, because the object reference only contains a handle to an object. To change or interrogate an object's internal state, you have to send messages to it.
If you clear all references to a particular object (with SET), you will be unable to send that object any more messages. In particular, you will not be able to destroy that object and de-allocate its storage (see the section Destroying Objects).
You send a message to an object to make it execute a method. The method executed has an identifier which matches the message.
If an object does not understand a message, it is passed up the method inheritance chain until it is recognized and executed (see the section Method Inheritance in the chapter Class Programs for more information). The method inheritance chain is not a consideration if you are the user of the object; it is part of the object's implementation details.
You send a message by using the INVOKE verb. For example:
invoke myClass "new" returning myObject
This sends message "new" to myClass; in this example myClass is an object reference referring to the class declared in the example in the previous section. The target of an invoke is always an object reference. Using and returning parameters are optional, and follow the same rules as a COBOL CALL statement.
You do not have to use a literal for the message name. You can also put a
message name into a
pic x(n) data item. For example:
move "new " to aMessage ... invoke myClass aMessage returning myObject
The data item used to store the message must be large enough to allow at least one space at the end of the message name. The run-time system needs the space to be able to find the end of the message name.
The results are unpredictable if you send a message and use the same variable for sending a parameter and returning a result. For example, do not code:
invoke myObject "add" using aValue returning aValue
When you create a new object, the run-time system allocates an object handle, and storage for the variables declared in the Object-Storage Section. Classes either provide their own methods for creating new object instances, or inherit them from a superclass.
Method "new" is implemented in class Base (part of the supplied Class Library) to create an instance of a single object. Send the message to a class and provide a variable to receive the object reference.
working-storage section. 01 anObject object reference. ... procedure division. ... invoke aClass "new" returning anObject
In this example, aClass returns a handle to a new instance of itself in object reference anObject. Some Class Library classes implement a version of "new" which expects one or more parameters for initialization. Some classes, for example Window, implement a "new" method which sends the newly created object the "initialize" message.
Consult the Class Library Reference to check the interface to the "new" method for a class you want to use. Object creation methods are always class methods. Not all types of objects are created with the "new" message; for example the collection objects are created by "ofReferences" and "ofValues" methods.
When an application has finished with an object it should destroy it, freeing the memory it uses. This is because Object COBOL does not yet implement automatic garbage collection.
The following sections explain object destruction in more detail:
To destroy an object, send it the "Finalize" message. For example:
invoke anObject "finalize" returning anObject
The "finalize" method is implemented in the Base class (part of the supplied Class Library) and inherited by all classes. When you finalize an object, the method returns a null object handle.
A null object handle is always taken to refer to the NilObject. Should you accidentally send a message to the NilObject it will raise a "doesNotUnderstand" exception.
You may have copies of the object handle to a finalized object in data items other than the one you used in the "finalize" message. Sending a message to an object handle after the object to which it refers has been finalized gives unpredictable results:
There is an Object COBOL run-time switch to prevent reuse of finalized object references - this ensures that you will always get a run-time error when you attempt to send a message to a finalized object (see the chapter Debugging Object COBOL Applications).
Some Class Library objects contain references to other objects (for example, collection objects). When you send the containing object "finalize", the objects it contains do not get finalized. If the only references you had to these objects were the ones held in the containing object, you can now no longer reach or destroy those objects.
Class library container objects, such as the collection objects, respond to the "deepFinalize" message. This destroys all the objects within the container as well as the container itself. You may want to consider implementing "deepFinalize" in any objects of your own which contain other objects, or reimplementing "finalize" to destroy contained objects.
Which is appropriate depends on the nature of the containing object. If the containing object is the sole owner of the objects, it should implement its own version of "finalize". If the containing object is storing objects as an access mechanism for other clients, it should only destroy them if it receives a "deepFinalize".
This topic provides some guidelines on destroying objects:
However, if you have passed an object to another part of your application, you may not know whether the object is still in use or not. You should establish rules which state whether or not an object passed to another object can be destroyed.
The supplied Class Library uses these rules:
An object which is no longer in use by an application, but which has not been destroyed is said to constitute a memory leak. See the section Finding Memory Leaks in the chapter Debugging Object COBOL Applications for more information.
Once you "finalize" an object, you must avoid sending messages to any reference which still points to that object otherwise results are unpredictable.
For example, do not code:
set objectA to objectB invoke objectB "finalize" returning objectB invoke objectA "aMessage"
The object handle held in objectA now points to a non-existent object. The code fragment below is a more subtle example of the same thing:
invoke objectA "setValue" using objectB invoke objectB "finalize" returning objectB
Unless objectA created its own copy of objectB and kept the handle to that, objectA now has an invalid object handle. All objects in the supplied Class Library create copies of any object you pass in as a parameter, with the exception of elements stored in collections.
Copyright © 1999 MERANT International Limited. All rights reserved.
This document and the proprietary marks and names used herein are protected by international law.
|Requirements-based Vocabulary Tutorial||Class Programs|