If code in a super procedure is to be general-purpose, so that it can serve any object procedure needing it, it must always refer back to the object procedure for handles or other values it needs to make calculations or execute code on behalf of the object. There are two ways you can do this:
  1. 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 SUPER statement 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.

  2. 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 SHARED variables 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.

Given this handle, the super procedure code can do one of two kinds of things:
  • It can run a procedure or function IN TARGET-PROCEDURE that returns the desired value. You can do this by defining functions with the name getproperty, 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-DATA attribute 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.