Note: Shared and global objects were a programming concept that was very important in older applications, but are not used in newer applications. They are being discussed here for those legacy applications that may still use them.

In every DEFINE statement so far in this book, there is a part of the valid syntax that is deliberately left out. Now is the appropriate time to explain why this is so and why this syntax is not something you should use frequently in new applications.

The concept is shared objects, which allow multiple procedures to share a definition and the object it defines without passing the object as a parameter. Using a variable definition as an example, this is the basic syntax for shared objects:
DEFINE [ [ NEW ] SHARED ] VARIABLE cString AS CHARACTER NO-UNDO.

The first procedure in the call stack to reference a shared object defines the shared object as NEW SHARED. This means that the AVM registers the definition and does not expect to find it already in the stack. Any subprocedures that want to share the object define it as SHARED. This means that the AVM searches up the call stack for a matching definition and points the shared definition in the subprocedure at the same memory location as the NEW SHARED object. In this way, both procedures can see and modify the value of the object, rather the same as if it were an INPUT-OUTPUT parameter between the two procedures.

The two definitions must match exactly in every way that affects storage and treatment of the object. For example, one definition of a shared object with the NO-UNDO keyword does not match another definition of the same object without it, because the NO-UNDO keyword affects how the AVM deals with changes to the object’s value at run time.

To make sure that the definitions of shared objects in different procedures always match, and to make it easy to make changes to them when necessary, you can define an include file for the definition (or for a set of definitions to a whole list of shared objects). The NEW keyword, which is the one difference between the first definition of the object and all subsequent definitions further down the call stack, acts as an include file parameter. The first procedure to define the object passes NEW as an include file parameter, and subsequent procedures pass nothing. For example, this include file defines a shared variable:
/* inclvar.i */
DEFINE {1} SHARED VARIABLE cMyVar AS CHARACTER NO-UNDO.
This main procedure includes the definition and makes it NEW SHARED:
{ inclvar.i NEW }.
And further definitions just reference the include file to define it as SHARED:
{ inclvar.i }
To see how this works, take another look at the simple example of MainProc.p and its subprocedure, SubProc.p, which illustrate the procedure call stack in a world of non-persistent procedures. Instead of passing parameters, this time the code shares a variable definition and a buffer definition, as shown here:
Figure 1. MainProc.p and SubProc.p

The NEW SHARED variables defined in MainProc.p are available to SubProc.p because the latter defines them as SHARED variables. You do not need to redefine them in the InternalProc internal procedure because you defined them at the level of the entire SubProc.p procedure file, and therefore scoped to the whole procedure.

In general, a NEW SHARED object is available to be used, with a matching SHARED object definition, anywhere below the NEW SHARED definition in the call stack.

There are several reasons why shared objects are more useful than parameters. One such reason is that the procedures do not need to identify exactly which objects they will share, unlike a parameter list, which must spell out in full and must be the same in both the calling and the called procedures. For example, MainProc.p could define any number of objects as NEW SHARED. SubProc.p would not have to define all of them. It is free to define as SHARED whichever objects it needs to use. It can ignore the rest. Some other external procedure further down the call stack from SubProc.p could then define any of these as SHARED and use them, regardless of whether SubProc.p defined them or not.

It is worth noting, if only for historical reasons, that shared objects date back to a time when the AVM supported neither parameters nor internal procedures, let alone persistent procedures. Therefore, they were the only mechanism available for sharing values between procedures.

Objects you can define as shared include variables, buffers, queries, temp-tables, browses, and frames, among others.