Guideline 2: Use TARGET-PROCEDURE to refer back to the object procedure
- Last Updated: September 12, 2023
- 5 minute read
- OpenEdge
- Version 13.0
- Documentation
- You can pass any needed values into the procedure call as input parameters. This
is a simple technique but not necessarily an effective one. For one thing,
putting values into parameters hard-codes the list of needed values forevermore.
This can lead to serious maintainability problems. Keep in mind that not only
every reference to the internal procedure or function, but also every
RUN SUPERstatement inside it, must duplicate the same parameter list. Any change to that list will be a maintenance nightmare. Also, specifying the needed parameters violates the object-oriented nature of the relationship between the two procedures in that it is forcing the object procedure to know something about the super procedure’s implementation of the internal procedure, namely what information it needs to operate on.Beyond this, it is often awkward to specify parameters for another reason. The object procedure itself probably does not need the information itself—it’s presumably going to be available to it somehow, through local variable names or whatever else—so the parameter would not be used by a localization of the routine in the object procedure, if there is one. The parameter is only needed when the local procedure passes control to a separately compiled procedure that does not have access to the local variable. This makes use of the parameter look awkward.
- A better and more object-oriented technique is to allow the super procedure to
refer back to values that the object procedure makes available. This technique
provides more independence between the user of the standard behavior and the
implementation of that behavior. The traditional ABL programming technique of
using
SHAREDvariables does not work in this case, because there is no top-down hierarchy of procedures to let ABL make those values available. The alternative is to allow the super procedure to refer back into the object procedure in some other way.
There are two techniques that illustrate ways to do this, both using the
TARGET-PROCEDURE built-in function.
When an object procedure runs a routine such as startMeUp and the
interpreter locates it in a super procedure, then within the startMeUp
code inside the super procedure the TARGET-PROCEDURE function evaluates
to the procedure handle of the object procedure where the routine was originally run.
Alternatively, if there is a local implementation of startMeUp in the
object procedure, which then executes a RUN SUPER statement, then the
super procedure code can likewise use TARGET-PROCEDURE to obtain the
procedure handle of the original object.
- It can run a procedure or function
IN TARGET-PROCEDUREthat returns the desired value. You can do this by defining functions with the namegetproperty, where the property name is the logical name of the value needed. For every piece of public data that an object makes available to other procedures, the procedure must define such a function. Alternatively, you can define a single function that takes the name of the property as an input parameter and returns its value. Within the limitations of what the object determines to be public data, any other procedure can retrieve needed values at will. - A second kind of technique is to make the values available through the object’s
procedure handle. For example, user application code can use the
PRIVATE-DATAattribute to store an object's properties: either a list of the values themselves, in some delimited form, or a handle of a buffer containing all of an object's properties.
Keep in mind that it is the nature of how handles are used in the language that once a procedure object in a given OpenEdge session has the handle of something defined in another procedure instance, it can operate on that handle exactly as the other procedure can. This rule applies to handles of visual controls such as fields, browses, buttons, dynamic buffer handles, dynamic query handles, and dynamic temp-table handles. This is part of what makes the super procedure mechanism so powerful, though it compromises the object-oriented nature of the procedures as well-isolated individual objects. Once you let another procedure gain access to your procedure by giving away, say, the frame handle for the frame your procedure defines, everything else related to that is freely available.
Another important point to keep in mind about TARGET-PROCEDURE is that
the AVM re-evaluates it every time a new procedure or function name is invoked. For
example, throughout the little example in this section, the value of
TARGET-PROCEDURE inside any version of startMeUp
is the procedure handle of the procedure in which startMeUp was
originally invoked (that is, the handle of the procedure where the original
RUN statement was located or, if that original RUN
statement was RUN startMeUp IN some-other-proc-hdl,
then the value of some-other-proc-hdl). This is true no matter how
many nested levels of RUN SUPER statements you go through. However, as
soon as some other routine is run, the value of TARGET-PROCEDURE
changes to be the procedure handle where that routine was run. Once any and all versions
of that new routine execute and control returns to some version of
startMeUp, then the value of TARGET-PROCEDURE pops
back to what it was before.
For this reason, it is important for super procedures to invoke other routines IN
TARGET-PROCEDURE if there is any chance that the newly run routine needs to
refer to TARGET-PROCEDURE itself. For example, if the
startMeUp code in the 2nd super procedure needs to run another
internal procedure called moreStartupStuff, then even if
moreStartupStuff is also implemented in the 2nd super procedure,
you should invoke it by using the RUN moreStartupStuff IN
TARGET-PROCEDURE statement if it needs to refer to
TARGET-PROCEDURE itself (for example, to retrieve another property
value from the object procedure). If you don’t do this, then the value of
TARGET-PROCEDURE inside moreStartupStuff becomes
the h2nd super procedure handle, which is not useful. This statement
also lets the object procedure localize moreStartupStuff if it needs
to. If you do not desire this behavior (that is, if you want this subprocedure to be
invisible to object procedures), then you should define
moreStartupStuff as PRIVATE, and then pass the
value of TARGET-PROCEDURE into it as a parameter if it is going to be
needed.