This chapter discusses:
PeopleCode language structure.
Data types.
Statements.
Functions.
Expressions.
Operators.
This chapter assumes that you are familiar with a programming language, such as C, Visual Basic, or Java.
In its fundamentals, PeopleCode syntax resembles other programming languages. Some aspects of the PeopleCode language, however, are specifically related to the PeopleTools environment. Definition name references, for example, enable you to refer to PeopleTools definitions, such as record definitions or pages, without using hard-coded string literals. Other language features, such as PeopleCode data types and metastrings, reflect the close interaction of PeopleTools and Structured Query Language (SQL). Dot notation, classes and methods in PeopleCode are similar to other object oriented languages, like Java.
Conventional data types include number, date, string. Use them for basic computing. Object data types instantiate objects from PeopleTools classes. The appropriate used of each data type is demonstrated where the documentation discusses PeopleCode that uses that data type.
Declare variables before you use them.
This section discusses:
Conventional data types.
Object data types.
See Also
PeopleCode includes these conventional data types:
Any
When variables and function return values are declared as Any, the data type is indeterminate, enabling PeopleTools to determine the appropriate type of value based on context. Undeclared local variables are Any by default.
Boolean
Date
DateTime
Float
Integer
Note. The Float and Integer data types should be used instead of Number only where a performance analysis indicates that the increased speed is useful and an application analysis indicates that the different representations won't affect the results of the computations.
Number
Object
String
Time
Considerations for Float, Integer, and Number Types
The Integer type is a number represented as a 32-bit signed twos complement number, so it has a range of -2,147,483,648 to 2,147,483,647.
The Float type is a number represented using the machine floating binary point (double precision) representation. This floating binary point representation is not appropriate for exact calculations involving decimal fractions; in particular, calculations involving money. For example, because a tenth (1/10 or .1) cannot be exactly represented in floating binary point, a floating binary point sum of .10 + .10 is not be equal to .20. The default number representation in PeopleCode is a floating decimal point representation, which avoids this difficulty.
Operations (other than division) are done using integer arithmetic if the operands are both integers and the destination is an integer, even if the variable is declared as the Number type. The destination is considered to be an integer if one of the following is true:
The destination is an assignment to an integer variable or parameter.
The destination is an array subscript.
The destination is the right-hand operand of a comparison and the left-hand operand is an integer.
The destination is a when-expression part of an evaluate statement, and the expression evaluated at the start of the evaluate statement is an integer.
The destination is a for-loop initial, limit, or step expression and the control variable of the for-loop is an integer.
Division (the / operator) is never performed using integer arithmetic. It's always performed using the floating-decimal-point arithmetic, even if the result variable is declared as an Integer type.
Follow these recommendations for assigning types to numbers:
Use Number for most application data values.
Use Integer when you are counting items, such as rows in a rowset.
Use Float only when you are tuning the code for performance (after it is already working).
In addition, you should only use the Float type when you are certain that the resulting loss of precision will not affect the application and that the increase in the speed of the computation makes a difference to the transaction. In general, few applications should use the Float type.
For most classes in PeopleTools, you need a corresponding data type to instantiate objects from that class.
See Understanding Objects and Classes in PeopleCode.
PeopleCode includes these data buffer access types:
Field
Record
Row
Rowset
PeopleCode includes these display data types:
AnalyticGrid
Chart
Grid
GridColumn
Page
PeopleCode includes these internet script data types:
Cookie
Request
Response
PeopleCode includes these miscellaneous data types:
AESection
AnalyticInstance
Array
Crypt
Exception
File
Interlink
BIDocs
Note. BIDocs and Interlink objects used in PeopleCode programs run on the application server can only be declared as type Local. You can declare Interlinks as Global only in an Application Engine program.
JavaObject
Note. JavaObject objects can only be declared as type Local.
Message
MCFIMInfo
OptEngine
PostReport
ProcessRequest
RowsetCache
SoapDoc
SQL
SyncServer
TransformData
Note. TransformData objects can only be declared as type Local.
XmlDoc
XmlNode
Use this data type for any ApiObject, such as a session object, a tree object, a component interface, a portal registry, and so on.
The following ApiObject data type objects can be declared as type Global:
Session
PSMessages collection
PSMessages
All tree classes (trees, tree structures, nodes, levels, and so on.)
All query classes
All other ApiObject data type objects (such as all the PortalRegistry classes) must be declared as Local.
Use comments to explain, preferably in language comprehensible to anyone reading your program, what your code does. Comments also enable you to differentiate between PeopleCode delivered with the product and PeopleCode that you add or change. This differentiation helps in your analysis for debugging and upgrades.
Note. Use comments to place a unique identifier marking any changes or enhancements that you have made to a PeopleSoft application. This makes it possible for you to search for all the changes you have made. This is particularly helpful when you are upgrading a database.
The following are the ways to insert comments into PeopleCode:
You can surround comments with /* at the beginning and */ at the end.
You can also use a REM (remark) statement for commenting.
Put a semicolon at the end of a REM comment. If you do not, everything up to the end of the next statement is treated as part of the comment.
You can surround commented text with <* at the start and *> at the end.
Use this type of comment to enclose one set of comments within another set. You generally use this when you're testing code and want to comment out a section that already contains comments.
Warning! In application classes you will see the use of /+ +/ style comments. Do not use these in your PeopleCode. These annotations are generated by the compiler. If you use them, they are removed by the system the next time you validate, compile, or save your PeopleCode. They are used to provide signature information on application class methods and properties, and are regenerated each time the compiler compiles your application class PeopleCode. Instead, use the standard commenting mechanisms listed above.
Note. Commented text cannot exceed a maximum of 16383 characters.
The following code sample shows comment formatting:
<* this program is no longer valid commenting out entire thing REM This is an example of commenting PeopleCode; /* ----- Logic for Compensation Change ----- */ /* Recalculate compensation change for next row. Next row is based on prior value of EFFDT. */ calc_next_compchg(&OLDDT, EFFSEQ, 0); /* Recalculate compensation change for current row and next row. Next row is based on new value of EFFDT. */ calc_comp_change(EFFDT, EFFSEQ, COMP_FREQUENCY, COMPRATE, CHANGE_AMT, CHANGE_PCT); calc_next_compchg(EFFDT, EFFSEQ, 0); *>
Note. All text between the <* and *> comment markers is scanned. If you have mismatched quotation marks, invalid assignments, and so on, you may receive an error when using this type of comments.
A statement can be a declaration, an assignment, a program construct (such as a Break statement or a conditional loop), or a subroutine call.
This section discusses:
Separators.
Assignment statements.
Language constructs.
Branching statements.
Conditional loops.
PeopleCode statements are generally terminated with a semicolon. The PeopleCode language accepts semicolons even if they’re not required, such as after the last statement completed within an If statement. This enables you to consistently add semicolons after each statement.
Extra spaces are ignored. They are removed by the PeopleCode Editor when you save the code.
The assignment statement is the most basic type of statement in PeopleCode. It consists of an equal sign with a variable name on the left and an expression on the right:
variableName = expression;
The expression on the right is evaluated, and the result is placed in the variable named on the left. Depending on the data types involved, the assignment is passed either by value or by reference.
Assignment by Value
In most types of assignments, the result of the right-hand expression is assigned to the variable as a newly created value, in the variable's own allocated memory area. Subsequent changes to the value of that variable have no effect on any other data.
Assignment by Reference
When both sides of an assignment statement are object variables, the result of the assignment is not to create a copy of the object in a unique memory location and assign it to the variable. Instead, the variable points to the object's memory location. Additional variables can point to the same object location.
For example, both &AN and &AN2 are arrays of type Number. Assigning &AN2 to &AN does not assign a copy of &AN2 to &AN. Both array objects point to the same information in memory.
Local array of number &AN, &AN2; Local number &NUM; &AN = CreateArray(100, 200, 300); &AN2 = &AN; &NUM = &AN[1];
In the code example, &AN2 and &AN point to the same object: an array of three numbers. If you were to change the value of &AN[2] to 500, and then reference the value of &AN2[2], you would get 500, not 300. On the other hand, assigning &NUM to the first element in &AN (100), is not an object assignment. It’s an assignment by value. If you changed &AN[1] to 500, then &NUM remains 200.
Note. In PeopleCode, the equal sign can function as either an assignment operator or a comparison operator, depending on context.
PeopleCode language constructs include:
Branching structures: If and Evaluate.
Loops and conditional loops: For, Repeat, and While.
Break, Continue, and Exit statements loop control and terminating programs.
The Return statement for returning from functions.
Variable and function declaration statements: Global, Local, and Component for variables, and Declare Function for functions.
The Function statement for defining functions.
Class definition statements.
Try, Catch, and Throw statements for error handling.
PeopleCode, like C, does not have subroutines as we generally refer to them. PeopleCode subroutines are the subset of PeopleCode functions only that are defined to return no value or to return a value optionally. Calling a subroutine is the same as calling a function with no return value:
function_name([param_list]);
See Also
Branching statements control program flow based on evaluation of conditional expressions.
The syntax of If, Then, and Else statements is:
If condition Then [statement_list_1] [Else [statement_list_2]] End-if;
This statement evaluates the Boolean expression condition. If condition is true, the If statement executes the statements in statement_list_1. If condition is false, then the program executes the statements in the Else clause; if there is no Else clause, the program continues on to the next statement.
Use the Evaluate statement to check multiple conditions. Its syntax is:
Evaluate left_term When [relop_1] right_term_1 [statement_list] . . . When [relop_n] right_term_n [statement_list] [When-other [statement_list]] End-evaluate;
The Evaluate statement takes an expression, left_term, and compares it to compatible expressions (right_term) using the relational operators (relop) in a sequence of When clauses. If relop is omitted, then the equal sign is assumed. If the result of the comparison is TRUE, the program executes the statements in the When clause, then moves on to evaluate the comparison in the following When clause. The program executes the statements in all of the When clauses for which the comparison evaluates to TRUE. If none of the When comparisons evaluates to True, the program executes the statement in the When-other clause, if one is provided. For example, the following Evaluate statement executes only the first When clause. &USE_FREQUENCY in the following example can only have one of three string values:
evaluate &USE_FREQUENCY when = "never" PROD_USE_FREQ = 0; when = "sometimes" PROD_USE_FREQ = 1; when = "frequently" PROD_USE_FREQ = 2; when-other Error "Unexpected value assigned to &USE_FREQUENCY." end-evaluate;
To end the Evaluate statement after the execution of a When clause, you can add a Break statement at the end of the clause, as in the following example:
evaluate &USE_FREQUENCY when = "never" PROD_USE_FREQ = 0; Break; when = "sometimes" PROD_USE_FREQ = 1; Break; when = "frequently" PROD_USE_FREQ = 2; Break; when-other Error "Unexpected value assigned to &USE_FREQUENCY." end-evaluate;
In rare cases you may want to make it possible for more than one When clause to execute, as shown in the following example:
evaluate &PURCHASE_AMT when >= 100000 BASE_DISCOUNT = "Y"; when >= 250000 SPECIAL_SERVICES = "Y"; when >= 1000000 MUST_GROVEL = "Y"; end-evaluate;
The For statement repeats a sequence of statements a specified number of times. Its syntax is:
For count = expression1 to expression2 [Step i]; statement_list End-for;
The For statement initializes the value of count to expression1, then increments count by i each time after it executes the statements in statement_list. The program continues in this loop until count is equal to expression2. If the Step clause is omitted, then i equals one. To count backwards from a higher value to a lower value, then use a negative value for i. You can exit a For loop using a Break statement.
The following example demonstrates the For statement:
&MAX = 10; for &COUNT = 1 to &MAX; WinMessage("Executing statement list, count = " | &COUNT); end-for;
See Also
Conditional loops, Repeat and While, repeat a sequence of statements, evaluating a conditional expression each time through the loop. The loop terminates when the condition evaluates to True. You can exit from a conditional loop using a Break statement. If the Break statement is in a loop embedded in another loop, the break applies only to the inside loop.
Repeat Statement
The syntax of the Repeat statement is:
Repeat statement_list Until logical_expression;
The Repeat statement executes the statements in statement_list once, then evaluates logical_expression. If logical_expression is false, the sequence of statements is repeated until logical_expression is true.
While Statement
The syntax of the While statement is:
While logical_expression statement_list End-while;
The While statement evaluates logical_expression before executing the statements in statement_list. It continues to repeat the sequence of statements until logical_expression evaluates to False.
See Also
This section discusses:
Supported functions.
Function definitions.
Function declarations.
Function calls.
Function return values.
Function naming conflicts.
See Also
Understanding Objects and Classes in PeopleCode
PeopleCode supports the following types of functions:
Built-in: The standard set of PeopleCode functions. These can be called without being declared.
Internal: Functions that are defined (using the Function statement) within the PeopleCode program in which they are called.
External PeopleCode: PeopleCode functions defined outside the calling program. These are generally contained in record definitions that serve as function libraries.
External non-PeopleCode: Functions stored in external (C-callable) libraries.
Note. PeopleSoft Analytic Calculation Engine provides its own set of built-in functions.
See Using Built-in Functions in Analytic Models.
In addition, PeopleCode supports methods. The main differences between a built-in function and a method are:
A built-in function, in your code, is on a line by itself, and does not (generally) have any dependencies.
You do not have to instantiate an object before you can use the function.
A method can only be executed by an object (using dot notation).
You must instantiate the object first.
PeopleCode functions can be defined in any PeopleCode program. Function definitions must be placed at the top of the program, along with any variable and external function declarations.
By convention, PeopleCode programs are stored in records whose names begin in FUNCLIB_, and they are always attached to the FieldFormula event.
Note. Application classes can provide an alternative, and sometimes cleaner, mechanism for separating out functionality than functions stored in FUNCLIBs.
See Also
If you call an external function from a PeopleCode program, you must declare the function at the top of the program. The syntax of the function declaration varies, depending on whether the external function is written in PeopleCode or compiled in a dynamic link library.
The following is an example of a function declaration of a function that is in another FUNCLIB record definition:
Declare Function UpdatePSLOCK PeopleCode FUNCLIB_NODES.MSGNODENAME FieldFormula;
See Also
Functions are called with this syntax:
function_name([param_list])
The parameter list (param_list),is a list of expressions, separated by commas, that the function expects you to supply. Items in the parameter list can be optional or required.
You can check the values of parameters that get passed to functions at runtime in the Parameter window of the PeopleCode debugger.
If the return value is required, then the function must be called as an expression, for example:
&RESULT = Product(&RAISE_PERCENT, .01, EMPL_SALARY);
If the function has an optional return value, it can be called as a subroutine. If the function has no return value, it must be called as a subroutine:
WinMessage(64, "I can't do that, " | &OPER_NICKNAME | ".");
Parameters are always passed to internal and external PeopleCode functions by reference. If the function is supposed to change the data the caller passes, you must also pass in a variable.
Built-in function parameters can be passed by reference or by value, depending on the function. External C function parameters can be passed by value or by reference, depending on the declaration and type.
See Also
Functions can return values of any supported data type; some functions do not return any value.
Optional return values occur only in built-in functions. You cannot define a function that optionally returns a value. Optional return values are typical in functions that return a Boolean value indicating whether execution was successful. For example, the following call to DeleteRow ignores the Boolean return value and deletes a row:
DeleteRow(RECORD.BUS_EXPENSE_PER, &L1_ROW, RECORD.BUS_EXPENSE_DTL, &L2_ROW);
The following example checks the return value and returns a message saying whether it succeeded:
if DeleteRow(RECORD.BUS_EXPENSE_PER, &L1_ROW, RECORD.BUS_EXPENSE_DTL, &L2_ROW) then WinMessage("Row deleted."); else WinMessage("Sorry -- couldn't delete that row."); end-if;
If you define a function with the same name as a built-in function, the function that you defined takes precedence over the built-in function.
Anytime you compile the PeopleCode in the PeopleCode Editor, a warning message appears in the Validate tab, indicating that a user-defined function has the same name as an existing built-in function.
In addition, if you select Compile All PeopleCode, an error message is generated in the log file for every user-defined function that has the same name as a built-in function.
The following is an example error message: User defined function IsNumber is overriding the builtin function of the same name. (2,98)
If you notice that you named a function the same as a built-in function, and that the built-in function does what you're trying to achieve, replace your function with a reference to the built-in function. The built-in function is probably more efficient. In addition, using the built-in function reduces confusion for people who maintain your code, because if they miss the warning message in the Validate tab, they might assume the built-in function is being called when it is not.
This section discusses:
Expression fundamentals.
Constants.
Functions as expressions.
System variables.
Metastrings.
Record field references.
Definition name references.
See Also
Expressions evaluate to values of PeopleCode data types. A simple PeopleCode expression can consist of a constant, a temporary variable, a system variable, a record field reference, or a function call. Simple expressions can be modified by unary operators (such as a negative sign or logical NOT), or combined into compound expressions using binary operators (such a plus sign or logical AND).
Definition name references evaluate to strings equal to the name of a PeopleTools definition, such as a record or page. They enable you to refer to definitions without using string literals, which are difficult to maintain.
Metastrings (also called meta-SQL) are special expressions used within SQL string literals. At runtime, the metastrings expand into the appropriate SQL for the current database platform.
PeopleCode supports numeric, string, and Boolean constants, as well as user-defined constants. It also supports the constant Null, which indicates an object reference that does not refer to a valid object.
Note. You can express Date, DateTime, and Time values by converting from String and Number constants using the Date, Date3, DateTime6, DateTimeValue, DateValue, Time3, TimePart, and the TimeValue functions. You can also format a DateTime value as text using FormatDateTime.
Numeric constants can be any decimal number. Some examples are:
7
0.8725
-172.0036
String constants can be delimited by using either single (') or double (") quotation marks. If a quotation mark occurs as part of a string, the string can be surrounded by the other delimiter type. As an alternative, you can include the delimiter twice. Some examples are:
"This is a string constant."
'So is this.'
'She said, "This is a string constant."'
"She said, ""This is a string constant."""
Use the following code to include a literal quotation mark as part of your string:
&cDblQuote = '"'; /* singlequote doublequote singlequote */
The following also produces a string with two double quotation marks in it:
&cDblQuote = """"; /* dquote dquote dquote dquote */
You can also directly embed the doubled double quotation mark in strings, such as:
&sImage = Char(10) | '<IMG SRC="%IMAGE(' | &pImageName | ')"';
Strings must be contained on a single line. If you need to create a multi-line string, you must use concatenation to connect the lines to be a single sting.
Boolean constants represent a truth value. The two possible values are True and False.
Null constants represent an object reference value that does not refer to a valid object. This means that calling a method on the object or trying to get or set a property of it fails. The Null constant is just the keyword Null.
You can define constants at the start of a PeopleCode program. Then you can use the declared constant anywhere that the corresponding value would be allowed. Constants can be defined as numbers, strings, or Boolean values.
User-defined constants can only be declared as Local.
The following is an example of user-defined constant declarations:
Constant &Start_New_Instance = True; Constant &Display_Mode = 0; Constant &AddMode = "A": Local Field &Start_Date; . . . MyFunction(&Start_New_Instance, &Display_Mode, &Add_Mode);
See Also
You can use any function that returns a value as an expression. The function can be used on the right side of an assignment statement, passed as a parameter to another function, or combined with other expressions to form a compound expression.
See Also
System variables are preceded by a percent (%) symbol whenever they appear in a program. Use these variables to get the current date and time, or to get information about the user, the current language, the current record, page, or component, and more.
See Also
Metastrings are special SQL expressions. The metastrings, also called meta-SQL, are preceded with a percent (%) symbol, and can be included directly in string literals. They expand at runtime into an appropriate substring for the current database platform. Metastrings are used in the following:
SQLExec
Scroll buffer functions (ScrollSelect and its relatives).
In PeopleSoft Application Designer to construct dynamic views.
With some rowset object methods (Select, SelectNew, Fill, and so on).
With SQL objects.
In PeopleSoft Application Engine.
With some record class methods (Insert, Update, and so on).
With COBOL.
See Also
Use record field references to retrieve the value stored in a record field, or to assign a value to a record field.
Record Field Reference Syntax
References to record fields have the following form:
[recordname.]fieldname
You must supply the recordname only if the record field and your PeopleCode program are in different record definitions.
For example, suppose that in a database for veterinarians you have two records, PET_OWNER and PET. A program in the record definition PET_OWNER must refer to the PET_BREED record field in the PET record definition as PET.PET_BREED.
However, a program in the PET record definition can refer to this same record field more directly as PET_BREED.
If the program is in the PET_BREED record field itself, it can refer to this record field using the caret (^) symbol.
The PeopleCode Editor replaces the caret symbol with the actual record field name.
You can also use object dot notation to refer to record fields, for example:
&FIELD = GetRecord(RECORD.PET_OWNER).GetField(FIELD.PET_BREED);
See Referencing Data in the Component Buffer.
A record field name consists of two parts, the record name and the field name, separated by a period.
The field names used in PeopleCode are consistent with the field names allowed in the field definition. Case is ignored, although the PeopleCode Editor for the sake of convention, automatically formats field names in uppercase. A field name can be 1 to 18 characters, consisting of alphanumeric characters determined by your current language setting in Microsoft Windows, and characters #, @, $, and _.
A record name can be 1 to 15 characters, consisting of alphanumeric letters determined by your current language setting in Microsoft Windows, and characters #, @, $, and _.
Definition name references are special expressions that reference the name of a PeopleTools definition, such as a record, page, component, business interlink, and so on. Syntactically, a definition name reference consists of a reserved word indicating the type of definition, followed by a period, then the name of the PeopleTools definition. For example, the definition name reference RECORD.BUS_EXPENSE_PER refers to the definition name BUS_EXPENSE_PER.
Generally, definition name references are passed as parameters to functions. If you attempt to pass a string literal instead of a definition name reference to such a function, you receive a syntax error.
You also use definition name references outside function parameter lists, for example in comparisons:
If (%Page = PAGE.SOMEPAGE) Then /* do stuff specific to SOMEPAGE */ End-If;
In these cases, the definition name reference evaluates to a string literal. Using the definition name reference instead of a string literal enables PeopleTools to maintain the code if the definition name changes.
If you use the definition name reference, and the name of the definition changes, the change automatically ripples through the code, so you do not have to change it or maintain it.
In the PeopleCode Editor, if you place your cursor over any definition name reference and right-click, you can select View Definition to open the definition.
In addition, for most definitions, if you specify a definition that hasn't been created in PeopleSoft Application Designer, you receive an error message when you try to save your program.
Legal and Illegal Definition Names
Legal definition names, as far as definition name references are concerned, consist of alphanumeric letters determined by your current language setting in Microsoft Windows, and the characters #, @, $, and _.
In some cases, however, the definition supports the use of other characters. You can, for example, have a menu item named A&M stored in the menu definition even though & is an illegal character in the definition name reference. The illegal character results in an error when you validate the syntax or attempt to save the PeopleCode.
You can avoid this problem in two ways:
Rename the definition so that it uses only legal characters.
Enclose the name of the definition in quotation marks in the reference, for example: ITEMNAME."A&M"
The second solution is a commonly used workaround in cases where the definition name contains illegal characters. If you use this notation, the definition name reference is not treated as a string literal: PeopleTools maintains the reference the same way as it does other definition name references.
Note. If your definition name begins with a number, you must enclose the name in quotation marks when you use it in a definition name reference. For example, CompIntfc."1_DISCPLIN_ACTN".
The following table summarizes the reserved words used in definition name references.
Reserved Word |
Common Usage |
BARNAME |
Used with transfers and modal transfers. |
BUSACTIVITY |
Used with TriggerBusinessEvent. |
BUSEVENT |
Used with TriggerBusinessEvent. |
BUSPROCESS |
Used with TriggerBusinessEvent. |
COMPINTFC |
Used with Component Interface Classes. |
COMPONENT |
Used with transfers and modal transfers, as well as for generating URLs. |
FIELD |
Used with methods and functions to designate a field. |
FILELAYOUT |
Used with the SetFileLayout File class method. |
HTML |
Used with the GetHTMLText function. |
IMAGE |
Used in with functions and methods to designate an image. |
INTERLINK |
Used with the GetInterlink function. |
ITEMNAME |
Used with transfers and modal transfers. |
MENUNAME |
Used with transfers and modal transfers. |
MESSAGE |
Used with Messaging functions and methods. |
MOBILEPAGE |
Used to identify a mobile page (used with transfers.) |
NODE |
Used with transfers and modal transfers, as well as generating URLs. |
PAGE |
Used with transfers and modal transfers to pass the page item name (instead of the page name), and with controls and other functions to pass the page name. |
PORTAL |
Used with transfers and modal transfers, as well as generating URLs. |
RECORD |
Used in functions and methods to designate a record. |
SCROLL |
The name of the scroll area in the page. This name is always equal to the primary record of the scroll. |
SQL |
Used with SQL definitions. |
STYLESHEET |
Used with style sheets. |
See Also
This section discusses.
Supported variable types.
User-defined variables.
User-defined variable declaration and scope.
Variable declaration.
User-defined variable initialization.
Scope of local variables.
Lifetime of local variables.
Restrictions on variable use.
Variables and functions.
Recursive functions.
State of shared objects using PeopleSoft Pure Internet Architecture.
See Also
PeopleCode supports these types of 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-Z and a-z, digits 0-9, and characters #, @, $, and _. |
|
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:
The variable is valid for the entire session.
The variable is valid while any page in the component in which the variable is defined stays active.
The variable is valid for the duration of the PeopleCode program or function in which the variable is defined.
You can declare variables using the Global, Local, or Component statements, or you can use local variables without declaring them. Here are some examples:
Local Number &AGE; Global String &OPER_NICKNAME; Component Rowset &MY_ROWSET; Local Any &SOME_FIELD; Local ApiObject &MYTREE; Local Boolean &Compare = True;
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.
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 variables remain defined and keep their values while any page in the component in which they’re defined remains active. Similar to a global variable, a component variable must be declared in each PeopleCode program where it’s used.
Component variables act the same as global variables when an Application Engine program is called from a page (using CallAppEngine).
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’re transferring within the same component or not.
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 function are valid to the end of the function and not beyond.
You can check the values of Local, Global, and Component variables at runtime in the different variable windows of the PeopleCode debugger. Local variables declared within a function are displayed in the Function Parameters window.
Declare variables before you use them. If you do not declare a variable, it's 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:
Validation tab with auto-declared variables
If you've 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, 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, 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 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.
There are two types of local variables: 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 are only local to that function.
See Recursive Functions.
A program-local variable can be affected by statements anywhere in the program. For example, suppose there are two functions in RECORD_A.FIELD_A.FieldFormula, FUNC_1 and FUNC_2, and both modify a local variable named &TEMP. They could affect each other, as they're both using 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 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's 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's Back button.
In general, the global state of the object is restored. If the object hasn't 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's 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
See Also
PeopleCode expressions can be modified and combined using math, string, comparison, and Boolean operators.
This section discusses:
Math operators.
Operations on dates and times.
String concatenation.
@ operator.
Comparison operators.
Boolean operators.
PeopleCode uses standard mathematical operators:
+
Add.
-
Subtract (or unary negative sign).
*
Multiply.
/
Divide.
**
Exponential.
Exponentiation occurs before multiplication and division; multiplication and division occur before addition and subtraction. Math expressions otherwise are evaluated from left to right. You can use parentheses to force the order of operator precedence.
The minus sign can also, of course, be used as a negation operator, as in the following expressions:
-10 - &NUM - Product(&PERCENT_CUT, .01, SALARY)
You can add or subtract two date values or two time values, which provides an Number result. In the case of dates, the number represents the difference between the two dates in days. In the case of time, the number represents the difference in seconds. You can also add and subtract numbers to or from a time or date, which results in another date or time. Again, in the case of days, the number represents days, and in the case of time, the number represents seconds.
The following table summarizes these operations:
Operation |
Result Type |
Result Represents |
Time + number of seconds |
Time |
Resulting time |
Date + number of days |
Date |
Resulting date |
Date - date |
Number |
Difference in days |
Time - time |
Number |
Difference in seconds |
Date + time |
DateTime |
Date and time combined |
The string concatenation operator ( | ) is used to combine strings. For example, assuming &OPER_NICKNAME is “Dave”, the following statement sets &RETORT to “I can’t do that, Dave.”
&RETORT = "I can't do that, " | &OPER_NICKNAME | "."
The concatenation operator automatically converts its operands to strings. This makes it easy to write statements that display mixed data types. For example:
&DAYS_LEFT = &CHRISTMAS - %Date; WinMessage("Today is " | %Date | ". Only " | &DAYS_LEFT | " shopping days left!");
The @ operator converts a string storing a definition reference into the definition. This is useful, for example, if you want to store definition references in the database as strings and retrieve them for use in PeopleCode; or if you want to obtain a definition reference in the form of a string from the operator using the Prompt function.
To take a simple example, if the record field EMPLID is currently equal to 8001, the following expression evaluates to 8001:
@"EMPLID"
The following example uses the @ operator to convert strings storing a record reference and a record field reference:
&STR1 = "RECORD.BUS_EXPENSE_PER"; &STR2 = "BUS_EXPENSE_DTL.EMPLID"; &STR3 = FetchValue(@(&STR1), CurrentRowNumber(1), @(&STR2), 1); WinMessage(&STR3, 64);
Note. String literals that reference definitions are not maintained by PeopleTools. If you store definition references as strings, then convert them with the @ operator in the code, this creates maintenance problems whenever definition names change.
The following function takes a rowset and a record, passed in from another program, and performs some processing. The GetRecord method does not take a variable for the record, however, you can dereference the record name using the @ symbol. Because the record name is never hard-coded as a string, if the record name changes, this code does not have to change.
Function Get_My_Row(&PASSED_ROWSET, &PASSED_RECORD) For &ROWSET_ROW = 1 To &PASSED_ROWSET.RowCount &UNDERLYINGREC = "RECORD." | &PASSED_ROWSET.DBRecordName; &ROW_RECORD = &PASSED_ROWSET.GetRow(&ROWSET_ROW).GetRecord(@&UNDERLYINGREC); /* Do other processing */ End-For; End-Function;
Comparison operators compare two expressions of the same data type. The result of the comparison is a Boolean value. The following table summarizes these operators:
Operator |
Meaning |
= |
Equal |
!= |
Not equal |
<> |
Not equal |
< |
Less than |
<= |
Less than or equal to |
> |
Greater than |
>= |
Greater than or equal to |
You can precede any of the comparison operators with NOT, for example:
Not=
Not<
Not>=
Expressions formed with comparison operators form logical terms that can be combined using Boolean operators.
String comparisons are case-sensitive. You can use the Upper or Lower built-in functions to do a case-insensitive comparison.
See Also
The logical operators AND, OR, and NOT are used to combine Boolean expressions. The following table shows the results of combining two Boolean expressions with AND and OR operators:
Expression 1 |
Operator |
Expression 2 |
Result |
FALSE |
AND |
FALSE |
FALSE |
FALSE |
AND |
TRUE |
FALSE |
TRUE |
AND |
TRUE |
TRUE |
FALSE |
OR |
FALSE |
FALSE |
FALSE |
OR |
TRUE |
TRUE |
TRUE |
OR |
TRUE |
TRUE |
The NOT operator negates Boolean expressions, changing a True value to False and a False value to True.
In complex logical expressions using the operations AND, OR, and NOT, NOT takes the highest precedence, AND is next, and OR is lowest. Use parentheses to override precedence. (It’s generally a good idea to use parentheses in logical expressions anyway, because it makes them easier to decipher.) If used on the right side of an assignment statement, Boolean expressions must be enclosed in parentheses.
The following are examples of statements containing Boolean expressions:
&FLAG = (Not (&FLAG)); /* toggles a Boolean */ if ((&HAS_FLEAS or &HAS_TICKS) and SOAP_QTY <= MIN_SOAP_QTY) then SOAP_QTY = SOAP_QTY + OrderFleaSoap(SOAP_ORDER_QTY); end-if;