Chapter 3: Using Objects in Programs

This chapter describes how you can use objects in programs. It uses examples of code to illustrate points. For full syntax definitions, see your Language Reference.

Overview

Objects can be used by an application which is not itself object-oriented. The same rules apply whether the program you write is an OO COBOL class, or a procedural COBOL program in which you want to use COBOL objects.

Programs that use objects all have certain features in common:

Generally, a program that uses objects sends a message to one or more factory 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.

Declaring Classes

If you want to use an object in a program, you must declare the object's class in the program's Repository paragraph. This prompts the Compiler to obtain information about the class from the external repository, which is an area where information about classes and interfaces is held. The availability of the external repository enables conformance checking to take place (see the section Conformance). Information about classes is added to the external repository when a class is compiled.

The CLASS clause also:

When you declare a class, it effectively makes the class's factory object available. The class names in the Repository paragraph are automatically declared as object reference data items. This enables you to send messages to the factory object.

The code below shows class registration for classes CharacterArray and Employee:

repository.
    class CharacterArray as "chararry"
    class Employee
    

If you code the AS clause, the Compiler uses the value of the literal as the external name of the class program; otherwise it uses the class name changed to upper case. If you are writing a class, you do not have to include a CLASS clause for the class you are writing; if you do include one, the Compiler ignores it and uses the class name or literal in the Class-ID paragraph in the Identification Division.

Micro Focus COBOL provides alternative syntax; see the section Summary of Syntax Alternatives in the chapter Micro Focus OO COBOL Alternative Syntax.

Using Object References

An object reference can hold a handle to a factory or instance object. Depending on the syntax you use, object references are untyped or typed. An untyped object reference data item can hold an object reference for any factory or instance object. Untyped object references are also known as universal object references. A typed object reference can only hold an object reference of the type specified by the syntax.

It is good programming practice to use typed object references rather than untyped; this is because they allow the Compiler to perform its conformance checking, which tends to lessen the number of run-time errors that occur. For more information on conformance checking see the section Conformance.

Declaring Object References

You need to declare data items of type OBJECT REFERENCE to hold handles to any objects you will be using.

For example:

01 anObject     usage object reference.
01 secdObject	usage object reference factory of BankAccount.	
01 thirdObject  usage object reference active-class.
01 fourthObject usage object reference Rentable.

The first line defines an untyped or universal object reference.

The second, third and fourth lines define typed object references:

You do not need to declare object references for the factory objects of the classes you are going to use in your program. These are declared automatically when you list your classes in the Repository paragraph.

Manipulating Object References

The only direct operations you can use on object references are:

No other operations are valid, because the object reference contains only 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, you will be unable to send that object any more messages. In particular, you will not be able to destroy that object and deallocate its storage (see the section Destroying Objects ).

You can 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.

Object Views

You can copy object references from one data item to another using the SET statement, but only if the receiving object reference is to a subclass of the class of the sending object reference. For example, if classes circle, triangle and rectangle all inherit from class shape, the following code is valid:

01 obj1 usage object reference class shape.
01 obj2 usage object reference class circle.
01 obj3 usage object reference class triangle.
01 obj4 usage object reference class rectangle.	
...
set obj1 to obj2
set obj1 to obj3
set obj1 to obj4

This syntax enables polymorphism; in this example you use it in order to execute the right methods for the particular shape you are processing, for example the method for calculating its area.

However, the following code is not valid:

set obj2 to obj1

This is because obj1 might not be pointing to a circle object. However, you might know that there are certain points in your program where obj1 does point to a circle object. Object views enable you to exploit this knowledge. In this example, you would recode your SET statement as follows:

set obj2 to obj1 as circle

This statement will be accepted at compile time. The presence of the object view "as circle" signals to the run-time system that it must check that obj1 is actually pointing to an object of class circle, before executing the statement. If the check fails, you get a run-time error.

The object view syntax also provides:

Sending Messages

You send a message to an object to make it execute a method. The method to be executed is named in 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 Classes for more information).

There are three ways of sending a message:

Using the INVOKE Statement

You can send a message by using the INVOKE statement. 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 statement 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

However, there is a disadvantage to using a data item: the object reference that precedes the message name data item, myClass in this example, must be a universal object reference, and hence the Compiler cannot do its usual conformance checking. For more information on conformance checking see the section Conformance.

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

Inline Method Invocation

You can invoke a method inline, as long as it has a returning parameter, by coding the object reference followed by the method and separated by two colons in place of an operand in a statement, for example:

move anAccount::"getBalance" to current-balance

This is equivalent to the following INVOKE statement:

invoke anAccount "getBalance" returning current-balance

Invocation Using Object Properties

You can invoke get property and set property methods using object properties. Get and set property methods are methods that are either generated automatically by the Compiler in response to object property syntax in data definitions, or coded by you using special syntax in the Method-ID paragraph. To invoke a get or set property method, you use a statement such as:

move balance of anAccount to current-balance

This statement invokes the get property method balance of the account object referred to by the object reference anAccount.

For more details see the section Get and Set Property Methods in the chapter Methods.

Conformance

Conformance is a quality that applies to interfaces. The term interface is used in two ways in OO COBOL:

Part of an object's interface (in the first sense) can be a set of methods that it provides because it implements an interface (in the second sense). Interfaces in the second sense are explained in more detail in the chapter Interfaces.

It is essential in OO programming that, when your program is executed, each object conforms to the interface that you defined for it. To help to ensure this, the Compiler provides conformance checking. In other words, as far as possible it ensures that your objects will conform at run-time to the interfaces you have described for them. If any conformance checks fail, the Compiler displays error messages. The more rigorously you use the OO COBOL syntax, the more thoroughly your program will be conformance checked.

Conformance checking relies on the existence of an external repository file, containing details of all the interfaces. The use of this file is controlled by the REPOSITORY Compiler directive, as follows:

Here are some examples of the kinds of checks included:

The Compiler uses the information in the external repository to perform conformance checking.

Creating a New Instance Object

When you create a new object, the run-time system allocates an object handle, and storage for the variables declared in the instance object's Working-Storage Section. You can create as many instances of any particular class of object as system resources allow; each has identical behavior, but its own unique data. Classes either provide their own methods for creating new object instances, or inherit them from a superclass.

The method "new" is implemented in the class Base (part of the supplied Base Class Library) to create an instance of a single object. To create an instance object, send the message to a class and provide a variable to receive the object reference.

For example:

 working-storage section.
 01  anAccount           object reference of BankAccount.
   ...
 procedure division.
    ...
    invoke BankAccount "new" returning anAccount

In this example, BankAccount returns a handle to a new instance of itself in object reference anAccount. 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 your Class Library Reference to check the interface to the "new" method for the class you want to use. Object creation methods are always factory methods.

Not all types of objects are created with the "new" message; for example the collection objects in the Micro Focus Base Class Library are created by "ofReferences" and "ofValues" methods. For more information about collections see the chapter Collection Frameworks.

Destroying Objects

Some OO programming languages perform garbage collection at run time, that is, they automatically destroy objects that are no longer in use. OO COBOL does not provide garbage collection. Once you create an object, it remains in existence until destroyed explicitly, even if the data item which holds its object handle is destroyed or goes out of scope.

There are two ways an object can be destroyed:

It is good programming practice to destroy unwanted objects in your applications, rather than leaving it to the run-time system. You should not destroy an object if it is still in use. 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 to govern whether or not an object passed to another object can be destroyed.

An object which is no longer in use by an application, but which has not been destroyed, is said to constitute a memory leak. The class Behavior, part of the Micro Focus Base Class Library, has a method that helps with finding memory leaks; for more information see the section Finding Memory Leaks in the chapter Compiling and Debugging OO COBOL Applications.

Object Destruction Methods

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 Micro Focus Base Class Library) and inherited by all classes.

Some class library objects contain references to other objects (for example, collection objects). When you send the "finalize" method to the containing object, the objects it refers to do not get destroyed. 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 method 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".

Finalized Object References

Once you have destroyed an object, you must avoid sending messages to any reference that still points to that object. For example, do not code:

set objectA to objectB
invoke objectB "finalize" returning objectB

The object handle held in objectA now points to a non-existent object.

Sending a message to an object handle after the object to which it refers has been finalized gives unpredictable results:

There is an OO 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 section Preventing Reallocation of Object Handles in the chapter Compiling and Debugging OO COBOL Applications).

If you create a copy of an object and keep the handle to the copy, you can destroy the original object without affecting the copy.

All objects in the supplied class libraries create copies of any objects you pass in as parameters and of any objects returned as parameters, with the exception of elements stored in collections.


Copyright © 2004 Micro Focus International Limited. All rights reserved.