Variables

This section discusses.

  • Supported variable types.

  • User-defined variables.

  • User-defined variable declaration and scope.

  • Variable declaration.

  • User-defined variable initialization.

  • Restrictions on variable use.

  • Scope of local variables.

  • Duration of local variables.

  • Variables and functions.

  • Recursive functions.

  • State of shared objects using PeopleSoft Pure Internet Architecture.

PeopleCode supports these types of variables:

Field or Control

Definition

User-defined variables

These variable names are preceded by an & character wherever they appear in a program. Variable names can be 1 to 1000 characters, consisting of letters A through Z and a through z, digits 0 through 9, and characters #, @, $, and _.

System variables

System variables provide access to system information. System variables have a prefix of the % character rather than the & character. Use these variables wherever you can use a constant, passing them as parameters to functions or assigning their values to fields or to temporary variables.

A user-defined variable can hold the contents of a record field for program code clarity. For example, you may give a variable a more descriptive name than a record field, based on the context of the program. If the record field is from another record, you may assign it to a temporary variable rather than always using the record field reference. This makes it easier to enter the program, and can also make the program easier to read.

Also, if you find yourself calling the same function repeatedly to get a value, you may be able to avoid some processing by calling the function once and placing the result in a variable.

The difference between the variable declarations concerns their life spans:

  • Global

    The variable is valid for the entire session.

    Global variables can be accessed from different components and applications, including an Application Engine program. A global variable must be declared, however, in each PeopleCode program where it’s used. Use global variables rarely, because they are difficult to maintain.

    Global variables are not available to a portal or applications on separate databases.

  • Component

    Component variables remain defined and keep their values while any page in the component in which they are defined remains active. Similar to a global variable, a component variable must be declared in each PeopleCode program where it is used.

    Component variables remain defined after a TransferPage, DoModal, or DoModalComponent function. However, variables declared as Component do not remain defined after using the Transfer function, whether you are transferring within the same component or not.

    Component variables act the same as global variables when an Application Engine program is called from a page (using CallAppEngine).

  • Local

    The variable is valid for the duration of the PeopleCode program or function in which the variable is defined.

    Local variables declared at the top of a PeopleCode program (or within the main, that is, non-function, part of a program) remain in scope for the life of that PeopleCode program. Local variables declared within a method or function are valid to the end of the method or function and not beyond.

You can explicitly declare variables using the Global, Component, or Local statements, or you can use local variables without declaring them. Here are some examples of explicit variable declarations:

Local Number &AGE; 
Global String &OPER_NICKNAME; 
Component Rowset &MY_ROWSET; 
Local Any &SOME_FIELD; 
Local ApiObject &MYTREE; 
Local Boolean &Compare = True;
Component PTFP_FEED:FeedFactory &cFeedFactory;

Variable declarations are usually placed above the main body of a PeopleCode program (along with function declarations and definitions). The exception is the Local declaration, which you can use within a function or the main section of a program. You can declare variables as any of the PeopleCode data types. If a variable is declared as an Any data type, or if a variable is not declared, PeopleTools uses an appropriate data type based on context.

Note: Declare a variable as an explicit data type unless the variable will hold a value of an unknown data type.

You can check the values of Global, Component, or Local variables at runtime in the different variable windows of the PeopleCode debugger. Local variables declared within a function appear in the Function Parameters window.

Declare variables before you use them. If you do not declare a variable, it is automatically declared with the scope Local and the data type Any. You receive a warning message in the Validation tab of the PeopleSoft Application Designer output window for every variable that is not declared when you save the PeopleCode program, as shown in the following example:

Image: Validation tab with auto-declared variables

The following image shows the validation tab with auto-declared variables.

Validation tab with auto-declared variables

If you declared all the variables, you can use these values to ensure you do not have misspellings. For example, if you declared a variable as &END_DATE and then accidentally spell it as &EDN_DATE, the “new variable” appears on the Validate tab when you save the program.

Another reason to declare variables is for the design-time checking. If you declare a variable of one data type and then assign to it a value of a different type, the PeopleCode Editor catches that assignment as a design-time error when you try to save the program. With an undeclared variable, the assignment error does not appear until runtime.

The following example produces a design-time error when you try to save the program:

Local Field &DATE; 
 
&DATE = GetRecord(RECORD.DERIVED_HR);

In addition, if you declare variables, the Find Object Reference feature finds embedded definitions. For example, suppose you wanted to find all occurrences of the field DEPT_ID. If you have not declared &MyRecord as a record, Find Object References does not find the following reference of the field DEPT_ID:

&MyRecord.DEPT_ID.Visible = False;

To declare and initialize variables in one step, use the following format:

Local String &MyString = "New";
Local Date &MyDate = %Date;

This method is available only for variables with the scope of Local.

Though you can declare more than one variable on a single line, you can only initialize one variable on a line. The following code creates a syntax error when you try to save the program:

Local Number &N1, &N2 = 5;

You cannot declare a variable, then initialize it in a second declaration statement. The following produces a duplicate declaration error when you try to save the program:

Global Number &N1; 
... 
Local String &N1 = "Str";  /* Duplicate definition. */

If you do not initialize variables, either when you declare them or before you use them, strings are initialized as Null strings, dates and times as Null, and numbers as zero.

The following data types can only be declared as Local:

  • JavaObject

  • Interlink

    Note: Interlink objects can be declared as type Global in an Application Engine program.

  • TransformData

  • XmlNode

The following ApiObject data type objects can be declared as Global:

  • Session

  • PSMessages collection

  • PSMessage

  • All tree classes (trees, tree structures, nodes, levels, and so on)

  • Query classes

All other ApiObject data type objects (such as all the PortalRegistry classes) must be declared as Local.

The two types of local variables are: program-local and function-local.

  • A program-local variable is declared as local in the main part of the program and is local to that program.

  • A function-local variable is declared as local inside a function and is local only to that function.

See Recursive Functions.

A program-local variable can be affected by statements anywhere in the program. For example, suppose RECORD_A.FIELD_A.FieldFormula has two functions, FUNC_1 and FUNC_2, and both modify a local variable named &TEMP. They could affect each other, as they both use the same variable name in the same PeopleCode program.

If, however, FUNC_3 is defined in RECORD_B_FIELD_B.FieldFormula and makes reference to &TEMP, it is not the same &TEMP as in RECORD_A.FIELD_A.FieldFormula. This difference becomes important when FUNC_1 calls FUNC_3. Technically, both functions exist at the same time, one inside the other, but &TEMP is a different variable for each of them. However, if FUNC_1 calls FUNC_2, then &TEMP is the same variable for both.

A local variable is valid for the duration of the PeopleCode program or function in which it is defined. A PeopleCode program is defined as what the PeopleCode Editor in Application Designer presents in a single window: a chunk of PeopleCode text associated with a single item (a record field event, a component record event, and so on.)

When the system evaluates a PeopleCode program and calls a function in the same PeopleCode program, a new program evaluation is not started.

However, when a function from a different PeopleCode program is called (that is, some PeopleCode text associated with a different item), the current PeopleCode program is suspended, and the Component Processor starts evaluating the new program. This means that any local variables in the calling program (called A) are no longer available. Those in the called program (called B) are available.

Even if the local variables in the A program have the same name as those in the B program, they are different variables and are stored separately.

If the called program (B) in turn calls a function in program A, a new set of program A's variables are allocated, and the called function in A uses these new variables. Thus, this second use of program A gets another lifetime, until execution returns to program B.

The following is an example of pseudocode to show how this might work. (This is non-compiled, non-working code. To use this example, you'd have to enter a similar program without the external declaration of the function in the other, not yet compiled, one.)

Program A (Rec.Field.FieldChange): 
local number &temp; 
declare function B1 PeopleCode Rec.Field FieldFormula; 
/* Uncomment this declaration and comment above to compile this the first time. 
   function B1 
   end-function; 
*/ 
 
function A1 
WinMessage("A1: &temp is " | &temp); 
&temp = &temp + 1; 
A2(); 
B1(); 
A2(); 
end-function; 
 
function A2 
WinMessage("A2: &temp is " | &temp); 
&temp = &temp + 1; 
end-function; 
 
A1(); 
 
Program B (Rec.Field.FieldFormula): 
local number &temp; 
declare function A2 PeopleCode Rec.Field FieldChange; 
 
function B1 
WinMessage("B1: &temp is " | &temp); 
&temp = &temp + 1; 
A2(); 
end-function;

When this is compiled and run, it produces the following output:

A1: &temp is 0
A2: &temp is 1
B1: &temp is 0
A2: &temp is 0
A2: &temp is 2

PeopleCode variables are always passed to functions by reference. This means, among other things, that a function can change the value of a variable passed to it so that the variable has the new value on return to the calling routine.

For example, the Amortize built-in function expects you to pass it variables into which it places the amount of a loan payment applied towards interest (&PYMNT_INTRST), the amount of the payment applied towards principal (&PYMNT_PRIN), and the remaining balance (&BAL). It calculates these values based on information that the calling routine supplies in other parameters:

&INTRST_RT=12; 
&PRSNT_BAL=100; 
&PYMNT_AMNT=50; 
&PYMNT_NBR=1; 
Amortize(&INTRST_RT, &PRSNT_BAL, &PYMNT_AMNT, &PYMNT_NBR, 
&PYMNT_INTRST, &PYMNT_PRIN, &BAL);
&RESULT = "Int=" | String(&PYMNT_INTRST) | " Prin=" | 
String(&PYMNT_PRIN) | " Bal=" | String(&BAL);

PeopleCode supports True recursive functions. A function can call itself, and each possibly recursive call of the function has its own independent copy of the parameters and function-local variables.

When writing recursive functions, be careful about passing variables as parameters, because PeopleCode implements such calls by reference. This means that if you call a function such as:

Function Func(&n as Number) 
&n = 3; 
End-Function;
local &x = 5;
Func(&x);

After the call to Func(&x), &x has the value 3, not 5. If the call was Func(Value(&x)), after the call &x is still 5.

Consider the following scenario:

  • A local and a global variable refer to the same object.

  • That object is used in a modal component.

  • Instead of completing the modal component, the user clicks the browser Back button.

In general, the global state of the object is restored. If the object has not been destroyed from the global state, the global state of the object is used for local references; otherwise, the local state is used for local references.

Here is an example:

Global array of number &Global_Array;
Local array of number &Local_Array;

&Global_Array = CreateArray(1, 2, 3);
&Local_Array = &Global_Array;
DoModal(Page.PAGENAME, "", - 1, - 1, 1, Record.SHAREDREC, 1);

/* return to here */
&Local_Array [1] = - 1;
&Global_Array [2] = - 2;
WinMessage(&Local_Array | " is " | &Local_Array.Join());
WinMessage(&Global_Array | " is " | &Global_Array.Join());

The following program, program 2, is located on the modal page the user is transferred to:

Global array of number &Global_Array;
&Global_Array[3] = -3;

The following program, program 3, is also located on the modal page:

Global array of number &Global_Array;
&Global_Array = CreateArray(1, 2, -3);

If program 2 is run, the output is the following:

&Local_Array is -1, -2, -3 
&Global_Array is -1, -2, -3

However, if program 3 is run, thereby destroying the original global state, the output is the following:

&Local_Array is -1, 2, 3
&Global_Array is 1, -2, -3