613-518-1166 info@zimdatabases.com

Selected Topics and White Papers

Methods

< All Topics

Defining a method

method mAdd(viSelf)
endMethod

The keywords METHOD and ENDMETHOD have replaced LOCALPROCEDURE and ENDPROCEDURE.

The above method declaration does not contain any behaviour. The class zCustomer below shows the class implementation, including behaviour for the add method.

%—————————————————————–
method mAdd(viSelf)
add Customer from aCustomer
endMethod

%—————————————————————–
method mDelete(viSelf)
delete sCustomer where ID = aCustomer.ID
endMethod

%—————————————————————–
method mpCustomer(viMethod, inout vtSelf)
change aCustomer let pMethod = viMethod
endMethod

%—————————————————————–
method mpFinalize(viSelf)
endMethod

%=================================================================
class zCustomer(viMethod, viSelf)
mpCustomer(viMethod,viSelf)
case
when aCustomer.pMethod = ‘add’
  mAdd(viSelf)
when aCustomer.pMethod = ‘ delete’
  mDelete(viSelf)
endCase
mpFinalize(viSelf)
endClass

Method Dispatcher

Method dispatcher calls the appropriate method defined in messages that are sent to the class.

The method dispatcher is placed in the class body as a CASE statement. No behaviour is coded in the method dispatcher, only in the methods of the class.

Public methods, methods that can be called by another class, have a fixed protocol of one parameter, viSelf.

Private methods, methods that can be only called by the containing class, have no fixed number of parameters. These methods are never called in the method dispatcher or in the class body, except for constructor and destructor methods.

Section 4.3 Layout and Style describes a template for the dispatcher.

Constructor and Destructor Methods

Each class has two standard private methods – constructor and destructor.

The constructor method, which derives its name from the base name (e.g. zCustomermpCustomer), is invoked when the class is instantiated or called. The destructor method, mpFinalize, executes any clean up operations.

Protocol

A class has two parameters:

viMethod is used to pass the method to be executed by the class. The method is passed to the class as a parameter and is directly assigned to the attribute structure to improve readability and ensure upward compatibility. This notation is similar to other object-oriented languages that reference methods using the dot notation; e.g. customer.add().

viSelf is used to pass the calling class base name. Passing this name allows a super-class that inherits a method to call or access the attributes of the subclass for run-time inheritance.

The base name is the name of the logical class. For example, the logical class CustomerTableUI is implemented as zCustomerTableUI (the class) and aCustomerTableUI (the attribute structure) in Zim.

Please review Section 3.6 for an example of run-time inheritance.

The message to an object consists of:

• data values assigned to the attribute structure

• any named sets

• the class call

• method

• self parameter

Inheritance

Inheritance provides a classification of objects that exploits their commonality. A hierarchy is formed where a child object inherits attributes and behaviour from a parent object. A parent may have many children, and that parent’s parent may have many children.

Figure 1: A class hierarchy

An example of a class hierarchy that is derived from an organization domain may look like this:

Figure 2: Class hierarchy derived from an organization domain

In this example, the Manager object inherits the attributes firstName and lastName from the object Person. It also inherits the methods (behaviour) new (specifies how to create a new person) and applyforLeave.

By creating a hierarchy, the Zim developer can programme by extension rather than by re-invention [LaLonde 90].

ZCS does not define any standard inheritance mechanism. Zim developers can choose between generated (early binding) or run-time (late-binding) inheritance.

Generated inheritance uses the class hierarchy to generate a single executable class from parent source files. For example, zManager maybe generated by three templates, tPerson, tEmpoyee, and tManager to produce one class file.

Runtime inheritance uses the class hierarchy to execute parent classes on the fly. For example, to execute the method applyForLeave, zManager calls zEmployee passing its parameters to the parent class.

The viSelf component of the protocol provides the mechanism for run-time inheritance. In generated inheritance this would be ignored, but not omitted. This allows a generated class library to call a class library based on run-time inheritance.

An Example of Run-time Inheritance

Please note the following is only an example and that the ZCS does not standardise a method for inheritance.

Continuing the example from the previous section, the class zManager inherits the method ’applyForLeave’ from zEmployee.

Figure 3: Manager inherits behaviour from Employee

In this example, the UI component zManagerUI calls zManager to ’applyForLeave’. The call (know as a delegation) within zManagerUI is implemented in Zim like this:

zManager(’applyForLeave’, ’’)

Note that viSelf is blank because the call is made across the hierarchy (a delegated call) not up the tree (an inherited call). The code for zManager appears below. Notice that the method ’applyForLeave’ does not exist in zManager and the method dispatcher calls zEmployee using the otherwise component of the case statement.

Note that zEmployee is an abstract class. This means that the class will only be executed using an inheritance call, not a delegated call. zEmployee is an abstraction of zManager.

The code for zManager is shown below followed by zEmployee.

%—————————————————————–
method mAssignEmployee(viSelf)
add ManagerEmployee from aManager
endMethod

%—————————————————————–
method mpManager(viMethod, inout vtSelf)
change aManager let pMethod = viMethod
let vtSelf = {vtSelf where vtSelf < ’’, ’zManager’}
endMethod

%—————————————————————–
method mpFinalize(viSelf)
endMethod

%=================================================================
class zManager(viMethod, viSelf)
mpManager(viMethod,viSelf)
%Methods
case
when aManager.pMethod = ‘assignEmployee’
  mAssignEmployee(viSelf)
otherwise
zEmployee(aManager.pMethod, viSelf)
endCase
mpFinalize(viSelf)
endClass

%—————————————————————–
method mApplyForLeave(viSelf)
change employee where ID = aEmployee.ID let ApplyForLeave=$true
endmethod

%—————————————————————–
method mpEmployee(viMethod,viSelf)
let = $replace(viSelf, 1, 1 a)
change aEmployee from a# let aEmployee.pMethod = viMethod
endMethod

%—————————————————————–
method mpFinalize(viSelf)
change a# from aEmployee
endMethod

%=================================================================
class zEmployee(viMethod, viSelf)
mpEmployee(viMethod,viSelf)
case
when aManager.pMethod = ‘applyForLeave’
  mApplyForLeave(viSelf)
endCase
mpFinalize(viSelf)
endClass

There are five points to note in the code of zEmployee.

1. mpEmployee moves the attributes across from aManager to aEmployee.

2. zEmployee manipulates the structure of aEmployee only.

3. mFinalize moves the modified attributes back to aManager.

An example of a class library using a complete run-time inheritance mechanism is the ZCL.

Please remember there are other variations of run-time inheritance that can be implemented. For example inheritance may be table driven. A child looks up a parent in a table and then the class is made to the parent. The parent still needs to know the child (for transferring of attribute values) and this is passed via viSelf.

Packages

Packages are a means to group classes into logical groups. The equivalent in Zim is the object directories. The directory allows you to manage a large group of classes and avoid naming conflicts. Classes are created in a directory exactly the same as other Zim objects.

 

 

Was this article helpful?
2.5 out Of 5 Stars
5 Stars 0%
4 Stars 0%
3 Stars 0%
2 Stars 100%
1 Stars 0%
How can we improve this article?
Table of Contents