8.1.2 Com_Owner, Com_Ancestor and Com_Self - Generic References to Components

Com_Owner

Com_Owner is commonly used throughout RDMLX and is a variable that always refers to the object in which the command is specified.

So, when adding controls to a component using the designer, or implementing events and method routines, any source code generated by the editor will refer to the component currently being edited using the generic name #COM_OWNER.

Define_Com Class(#PRIM_LABL) Name(#Label) Parent(#COM_OWNER)

OR

Evtroutine Handling(#Com_Owner.Initialize)

#Com_owner.Prepare

Endroutine

As a large percentage of code typically needs to refer to the current location, the use of the generic Com_owner to mean 'here' greatly simplifies code understanding.  It also means that copied code can be pasted directly in to a target without the need to update component references with specific class names.

For relatively simple applications that don't use inheritance beyond a single level, there is no reason to move away from the use of Com_Owner.  However, where multiple layers of inheritance are being used, Com_Ancestor and Com_Self can be used to execute code defined in the different layers of the inheritance hierarchy.

Com_Ancestor

Com_Ancestor refers directly to the class specified as the ancestor of the current component.

Thus, when in an application that uses inheritance, we might define basic behavior in a base ancestor class but override that behavior by redefining the method in the inheriting class.  At execution time the processing in the ancestor class will be ignored and the redefined method will be executed.

Mthroutine Name(Prepare) Options(*Redefine)

* Class specific processing

Endroutine

Whilst this typical use of a redefined method is often desirable, there may also be circumstances where rather than wanting to completely change the processing, we simply need to augment it.  To enable this we might write the following


Mthroutine Name(Prepare) Options(*Redefine)

#Com_Ancestor.Prepare

* Class specific processing

Endroutine

Here, the method is redefined but the very first line of the new method causes the ancestor version of the method to be executed.  This technique is typically used when a change to the ancestor processing is the exception rather than the rule.

Com_Self

Com_Self and Com_owner are very similar in use apart from one very distinct difference.  While Com_owner always refers to the current component, Com_Self refers to the current component taking into consideration any redefined methods further up the inheritance chain.

In the previous Com_ancestor example, redefining the method represented the exceptional case, but in a scenario where it is commonplace, the need to remember to execute ancestor code can cause complications.  In this situation it is better to drive the processing from the ancestor class.

Thus in the Ancestor we might have something similar to the following.

Mthroutine Name(Prepare)

* Run base code then class specific code
#Com_owner.PrepareBase

#Com_Self.PrepareSelf

Endroutine

Mthroutine Name(PrepareBase) Options(*Final)

* Base class processing
* Final – This method cannot be redefined

Endroutine

Mthroutine Name(PrepareSelf)

* Redefine in inheriting classes

Endroutine

In the inheriting class we would then see:

Mthroutine Name(PrepareSelf) Options(*Redefine)

* Class specific processing here

Endroutine

At runtime, invoking the Prepare method would result in the PrepareBase method being executed.  However, because the invocation of PrepareSelf uses Com_Self, the runtime looks further up the inheritance chain for a redefined version and executes that rather than the version of the method defined in the ancestor.

Unfortunately, it is all too easy to accidentally use Com_owner rather than Com_Self and a common issue found during development is that redefined code is never actually executed because Com_owner has been used instead of Com_Self.