Variables
A variable is the name of a location in which a value can be stored. Within ObjectScript, a variable does not have data type associated with it and you do not have to declare it.
Commonly, you use the SET command to define a variable by assigning it a value. You can assign a null string ("") value to a variable. Most commands and functions require a variable to be defined before it is used. If the variable is undefined, by default referencing it generates an <UNDEFINED> error. You can change InterSystems IRIS® data platform behavior to not generate an <UNDEFINED> error when referencing an undefined variable by setting the %SYSTEM.Process.Undefined()Opens in a new tab method.
You can use an undefined variable in some operations, such as the READ command, the $INCREMENT function, the $BIT function, and the two-argument form of the $GET function. These operations assign a value to the variable. The $DATA function can take an undefined or defined variable and returns its status.
Categories of Variables
Within ObjectScript, there are several kinds of variables, as follows:
-
Global variables (also known as globals)
-
Special variables (also known as system variables)
Each of these is used for a specific purpose and may have different scoping rules.
Unlike many computer languages, ObjectScript does not require variables to be declared. A variable is created when it is assigned a value. ObjectScript is a “typeless” language; a variable can receive data of any type. For further details on these topics refer to Variable Declaration and Variable Typing and Conversion.
Subscripted Variables
Local variables, process-private variables, and global variables can all take subscripts. The subscript conventions for all types of variables are similar:
-
A subscript can be a numeric or a string. It can include any characters, including Unicode characters. Valid numeric subscripts include positive and negative numbers, zero, and fractional numbers. The empty string ("") is not a valid subscript.
-
Subscript values are case-sensitive.
-
A numeric subscript is converted to canonical form. Thus, ^a(7), ^a(007), ^a(7.000), and ^a(7.) are all the same subscript. A string subscript is not converted to canonical form. Thus ^a(“7”), ^a(“007”), ^a(“7.000”), and ^a(“7.”) are different subscripts. The string subscript ^a(“7”) is the same as the numeric subscript ^a(7).
-
There is a maximum length for any subscript. Exceeding the maximum subscript length results in a <SUBSCRIPT> error:
-
For a local array, the maximum length of a subscript is 32767 encoded bytes.
-
For a global array, the maximum length of a subscript is 511 encoded bytes.
Note that in each case, the corresponding number of characters depends on the characters in the subscript and the current locale.
Also, the longest permitted integer is 309 digits; exceeding this limit results in a <MAXNUMBER> error. Therefore, a numeric subscript longer than 309 characters must be specified as a string.
-
-
The maximum number of subscript levels for a local variable is 255. The maximum number of subscript levels for a global or process-private global is 253. Exceeding the maximum number of subscript levels results in a <SYNTAX> error.
Actual maximums depend on several factors. For further details on global maximums, refer to Global Structure chapter in Using Globals.
Lock name subscripts follow the same conventions as variable subscripts.
Array Variables
An array variable is simply a variable with one or more subscript levels. Subscripts are enclosed in parentheses. Subscript levels are separated by commas. Any variable (with the exception of special variables) can be used as an array, as shown in the following example:
SET a(1) = "A local variable array"
SET a(1,1,1) = "Another local variable array"
SET ^||a(1) = "A process-private global array"
SET ^a(1) = "A global array"
SET obj.a(1) = "A multidimensional array property"
For local variables, the maximum number of subscript levels is 255. For global variables, the maximum number of subscript levels depends on the length of the subscript names. For subscript conventions and limits, refer to the Global Structure chapter in Using Globals.
Object Properties
An object property is a value associated with, and stored within, a specific instance of an object. Strictly speaking, an object property is not a variable, but syntactically you can use an object property in exactly the same way as any other local variable.
There are several types of property references: oref.property, ..property, and i%property. The object reference (oref) must be a local variable, not an expression. The property reference can reference a single-value property or a subscripted multidimensional property. There can be chained property references like oref.prop1.prop2.
The following example shows a property reference used as a variable:
// Create an Address object
SET address = ##class(Sample.Address).%New()
// Use the properties of the object
SET address.City = "Boston"
WRITE "City: ",address.City,!
There are some limitations for the use of property references as variables. A property of any type cannot be modified using SET $BIT() or SET $LISTBUILD(); a non-multidimensional property cannot be modified using SET $EXTRACT(), SET $LIST(), or SET $PIECE(). $DATA(), $GET(), and $INCREMENT() can only take a property if the property is multidimensional. Properties cannot be used with the MERGE command. These operations can be done within an object method using the instance variable syntax i%PropertyName.
Local Variables
A local variable is a variable that is stored within the current InterSystems IRIS process. It is accessible only to the process that created it. It is mapped to be accessible from all namespaces. When a process ends, all of the processes’ local variables are deleted.
InterSystems IRIS does not treat a SET or KILL of a local variable as a journaled transaction event; rolling back the transaction has no effect on these operations.
Naming Conventions
Define a local variable using the following naming conventions:
-
A local variable name must be a valid identifier. Its first character must be either a letter or the percent (%) character. Variable names starting with the “%” character are known as “percent variables” and have different scoping rules. Only variables that begin with “%Z” or “%z” are available for application code; all other percent variables are reserved for system use according to the rules described in “Rules and Guidelines for Identifiers” in the Orientation Guide for Server-Side Programming. The percent (%) character can only be used as the first character of a local variable name. The other characters of a local variable name may be letters or numbers.
-
Any word can be used as a variable name. However, it is strongly recommended that a variable name not be the name of an ObjectScript command or an SQL reserved word.
-
Local variable names are case-sensitive. For example: MYVAR, MyVar, and myvar are three different local variables.
-
Local variable names may include letter characters above ASCII 255 (Unicode letters).
-
Local variable names must be unique for the current process. Other processes may have local variables with the same name. A process-private global or a global may have the same name as a local variable. For example: myvar, ^||myvar, and ^myvar are three different variables.
-
Local variable names are limited to 31 characters. You may specify a name longer than 31 characters, but only the first 31 characters are used. Therefore, a local variable name must be unique within its first 31 characters.
-
Local variables can take subscripts. By using subscripts, you can define a local variable as an array of values. A subscript can be a number or a character string; it can include Unicode characters.
The %IS utility sets several local variables with all-uppercase names. These variable names should be avoided in situations where %IS is invoked. For further details, see I/O Devices and Commands in the I/O Device Guide.
Invalid Names
A local variable name that does not follow the above naming conventions generates a <SYNTAX> error. There is one exception: if a variable name begins with an underscore character followed by a letter, the system generates a <_CALLBACK SYNTAX> error. For example, SET x=_a.
A valid variable name prefaced by a caret (^) is a global variable, not a local variable.
A valid variable name prefaced by an at sign (@) is an indirection operator followed by a local variable name.
Scope of Local Variables
In ObjectScript code, all local variables are public, and can thus be accessed by any operation executed by that process in the current context. Access to a local variable value is restricted as follows:
-
The NEW command creates a new local variable context. An argumentless NEW creates a new context in which none on the existing local variables are defined. NEW var creates a new context in which the local variable var is not defined. The QUIT command reverts to the prior local variable context.
-
Within a procedure block local variables are private by default. A private local variable is only defined within that procedure block.
Local variables within a procedure block behave as follows:
-
Private variables. A local variable used within a procedure block is a private variable and is only defined within that procedure block, unless it is declared a public variable or it is a % variable. By default, all object methods created with Studio use procedure blocks (the ProcedureBlock class keyword is set within the class definition) and so, by default, all variables created in methods are private variables. You cannot use the NEW command on a private variable in a procedure block.
-
Public variables. A procedure block can explicitly declare a list of local variables as public variables. These variables values are accessible outside the procedure block. This comma-separated list of public variables can include non-existent variables and % variables. You can use the NEW command on a public variable in a procedure block.
A public variables list for the two local variables var1 and var2 is specified as follows: MyProc(x,y) [var1,var2] PUBLIC { code body }. (Note that the PUBLIC keyword specifies that the procedure is public; it has nothing to do with the public variables list.) Public variables are specified as a comma-separated list. Only unsubscripted local variables can be specified; specifying an unsubscripted variable in the public variables lists makes all of its subscript levels public as well. Only a simple object reference (OREF) can be specified; specifying an OREF in the public variables lists makes all of its object properties public as well. The list of public variables can include undefined variables.
-
% Variables. A local variable whose name starts with “%” is automatically declared a public variable. This makes it possible to define variables that are visible to all code within a process without having to explicitly list these variables as public. Only variables that begin with “%Z” or “%z” are available for application code; all other % variables are reserved for system use according to the rules described in “Rules and Guidelines for Identifiers” in the Orientation Guide for Server-Side Programming. You can use the NEW command on a % variable in a procedure block.
These mechanisms are described in greater detail in the Procedure Variables section of the “Callable User-defined Code Modules” chapter.
-
-
The XECUTE command defines local variables as public by default. You can explicitly define a local variable as private within the XECUTE command. Refer to XECUTE for more on explicitly defining local variables as either private or public.
You can use the WRITE or ZWRITE command, with no arguments, to list all currently defined local variables. You can use the $QSUBSCRIPT function to return the components (name and subscripts) of a specified local variable, or the $QLENGTH function to return the number of subscript layers. You can use the KILL command to delete local variables.
Object Values
An object value refers to an instance of an in-memory object. You can assign an object value to any local variable:
SET person = ##class(Sample.Person).%New()
WRITE person,!
The value of person is that of an object reference (OREF) converted into a string. This string or its value cannot be used to load an object from the database.
You can refer to the methods and properties of an object using dot syntax:
SET person.Name = "El Vez"
You can determine if a variable contains an object using the $ISOBJECT function:
SET str = "A string"
SET person = ##class(Sample.Person).%New()
WRITE "Is string an object? ", $IsObject(str),!
WRITE "Is person an object? ", $IsObject(person),!
You cannot assign an object value to a global. Doing so will result in a runtime error.
Assigning an object value to a variable (or object property) has the side effect of incrementing the object’s internal reference count. When the number of references to an object reaches 0, InterSystems IRIS will automatically destroy the object (invoke its %OnClose() callback method and remove it from memory). For example:
SET person = ##class(Sample.Person).%New() // one reference to Person
SET alias = person // two references
SET person = "" // 1 reference
SET alias = "" // no references left, object destroyed
Process-Private Globals
A process-private global is a variable that is only accessible by the process that created it. When the process ends, all of its process-private globals are deleted.
-
Process-specific: a process-private global can only be accessed by the process that created it, and cease to exist when the process completes. This is similar to local variables.
-
Always public: a process-private global is always a public variable. This is similar to global variables.
-
Namespace-independent: a process-private global exists independent of namespace. It is mapped to be accessible from all namespaces. Thus it can be created, accessed, and deleted regardless of current namespace. This differs from both local variables and global variables, which are both namespace-specific.
-
Unaffected by argumentless KILL, NEW, WRITE, or ZWRITE. A process-private global can be specified as an argument to KILL, WRITE, or ZWRITE. This is similar to global variables.
Process-private globals are intended to be used for large data values. They can serve, in many cases, as a replacement for the use of the Mgr/Temp directory, providing automatic cleanup at process termination.
InterSystems IRIS does not treat a SET or KILL of a process-private global as a journaled transaction event; rolling back the transaction has no effect on these operations.
Naming Conventions
A process-private global name takes one of the following forms:
^||name
^|"^"|name
^["^"]name
^["^",""]name
These four prefix forms are equivalent, and all four refer to the same process-private global. The first form (^||name) is the most common, and the one recommended for new code. The second, third, and fourth forms are provided for compatibility with existing code that defines globals. They allow you to specify a variable that determines whether to define name as a process-private global or a standard global. This is shown in the following example:
SET x=1 // toggle storage type
IF x=1 {
SET a="^" // for a process-private global
}
ELSE {
SET a="" // for a standard global
}
SET ^|a|name="a value"
Process-private globals use the following naming conventions:
-
A process-private global name must be a valid identifier. Its first character (after the second vertical bar) must be either a letter or the percent (%) character. The percent (%) character can only be used as the first character of a process-private global name. Only percent variables that begin with “%Z” or “%z” are available for application code (such as ^||%zmyppg or ^||%Z123); all other percent variables are reserved for system use according to the rules described in “Rules and Guidelines for Identifiers” in the Orientation Guide for Server-Side Programming.
The second and subsequent characters of a process-private global name may be letters, numbers, or the period character. A period cannot be used as the first or last character of the name.
-
A process-private global name cannot contain Unicode letters (letter characters above ASCII 255). Attempting to include a Unicode letter in a process-private global name results in a <WIDE CHAR> error.
-
Process-private global names are case-sensitive.
-
A process-private global name must be unique within its process.
-
Process-private global names are limited to 31 characters, exclusive of the prefix characters. You may specify a name longer than 31 characters, but only the first 31 characters are used. Therefore, a process-private global name must be unique within its first 31 characters.
-
Process-private globals can take subscripts. By using subscripts, you can define a process-private global as an array of values. A subscript can be a number or a character string; it can include Unicode characters. For subscript conventions, limitations on the number of subscript levels, and other information about use of subscripts, refer to Global Structure in Using Globals.
Listing Process-Private Globals
You can use the ^$||GLOBAL() syntax form of ^$GLOBAL() to return information about process-private globals belonging to the current process.
You can use the ^GETPPGINFO routine to display the names of all current process-private globals and their space allocation, in blocks. ^GETPPGINFO does not list the subscripts or values for process-private globals. You can display process-private globals for a specific process by specifying its process Id (pid), or for all processes by specifying the "*" wildcard string. You must be in the %SYS namespace to invoke ^GETPPGINFO.
The following example uses ^GETPPGINFO to list the process-private globals for all current processes:
SET ^||flintstones(1)="Fred"
SET ^||flintstones(2)="Wilma"
NEW $NAMESPACE
SET $NAMESPACE="%SYS"
DO ^GETPPGINFO("*")
The ^GETPPGINFO routine takes arguments as follows:
do ^GETPPGINFO("pdf","options","outfile")
These arguments are as follows:
-
pdf can be a process Id or the * wildcard.
-
options can be a string containing any combination of the following characters:
-
b (return values in bytes)
-
Mnn (list only processes with process-private globals that use nn or more blocks)
Use M0 to include processes without any process-private globals in the listing.
Use M1 to exclude processes without any process-private globals from the listing, but include processes having only a global directory block. (This is the default.)
Use M2 to exclude processes without any process-private globals from the listing, as well as those having only a global directory block.
-
S (suppress screen display; used with outfile)
-
T (display process totals only).
-
-
outfile is the file path for a file in CSV (comma-separated values) format that will be used to receive ^GETPPGINFO output.
The following example writes process-private globals to an output file named ppgout. The S option suppresses screen display; the M500 option limits output to only processes with process-private globals that use 500 or more blocks:
NEW $NAMESPACE
SET $NAMESPACE="%SYS"
DO ^GETPPGINFO("*","SM500","/home/myspace/ppgout")
Globals
A global is a special kind of variable that is automatically stored within the InterSystems IRIS database. It is mapped to a specific namespace, and can only be accessed within that namespace, unless an extended reference is used. A global can be accessed by any process. A global persists after the termination of the process that created it. It persists until explicitly deleted.
InterSystems IRIS treats a SET or KILL of a global as a journaled transaction event; rolling back the transaction reverses these operations. Locks may be used to prevent access by other processes to changes to a global until the transaction that made the changes has been committed. Refer to the “Transaction Processing” chapter for further details.
Within an ObjectScript program, you can use a global in the same way as any other variable. Syntactically, a global name is distinguished by a caret (“^”) character followed by a letter or a “%” character:
SET mylocal = "This is a local variable"
SET ^myglobal = "This is a global stored in the current namespace"
The naming conventions for globals are as follows:
-
A global consists of a global prefix and a global name. The global prefix is commonly a caret (^) character, specifying a global in the current namespace. A global prefix can also be an extended reference, such as ^|"samples"|, specifying a global in another namespace.
-
A global name must be a valid identifier. Its first character (after the prefix character(s)) must be either a letter or the percent (%) character. Only percent variables that begin with “%Z” or “%z” are available for application code (such as ^%zmyglobal or ^%Z123); these ^%Z and ^%z globals are written to the IRISSYS database, and are therefore preserved when you upgrade InterSystems IRIS. All other percent variables are reserved for system use according to the rules described in “Rules and Guidelines for Identifiers” in the Orientation Guide for Server-Side Programming.
The second and subsequent characters of a global name may be letters, numbers, or the period character. A period cannot be used as the first or last character of the name.
-
A global name cannot contain Unicode letters (letter characters above ASCII 255). Attempting to include a Unicode letter in a global name results in a <WIDE CHAR> error.
-
Global names are case-sensitive.
-
A global name must be unique within its namespace.
-
Global names are limited to 31 characters, exclusive of the prefix characters. You may specify a name longer than 31 characters, but only the first 31 characters are used. Therefore, a global name must be unique within its first 31 characters.
-
Globals can take subscripts. By using subscripts, you can define a global as an array of values. A subscript can be a number or a character string; it can include Unicode characters. For subscript conventions, limitations on the number of subscript levels, and other information about use of subscripts, refer to Global Structure in Using Globals.
-
Some global names are reserved for InterSystems use. For further details, refer to “Global Variable Names to Avoid” in the Orientation Guide for Server-Side Programming.
Optionally, a global may specify an extended reference that defines its namespace or directory using a pair of vertical bars or square brackets immediately after the caret characters (for example: ^|"samples"|myglobal or ^|""|myglobal). These extended global references should not be confused with process-private globals.
You can use the $ZREFERENCE special variable to determine the name of the most recently used global. You can use the $QSUBSCRIPT function to return the components of a specified global, or the $QLENGTH function to return the number of subscript layers.
For much more information on globals, refer to Using Globals.
Special Variables
ObjectScript includes a number of built-in special variables (also referred to as system variables) that are used to make certain system information available to applications. All special variables are supplied with InterSystems IRIS and are named with a “$” character prefix. Users cannot define additional special variables. The set of special variables is mapped to be accessible from all namespaces.
The value of a special variable is set to the current state of some aspect of your operating environment. Some special variables are initially set to the null string (""); referencing a special variable should never generate an <UNDEFINED> error. The value of a special variable is specific to the current process and cannot be accessed from another process.
Users can set some special variables with the SET command; other special variables are not user-modifiable. Refer to the individual special variables for further details.
The following example uses the special variable $HOROLOG:
SET starttime = $HOROLOG
HANG 5
WRITE !,$ZDATETIME(starttime)
WRITE !,$ZDATETIME($HOROLOG)
The special variable $HOROLOG stores the current system date and time. The SET command uses this special variable to set the user-defined local variable starttime to this value. The HANG command then suspends the program for 5 seconds. Finally, the two $ZDATETIME functions return starttime and the current system date and time in a user-readable format.
Other examples of special variables include:
WRITE !,"$JOB = ",$JOB // Current process ID
WRITE !,"$ZVERSION = ",$ZVERSION // Version info
Many special variables are read-only; they cannot be set using the SET command. Other special variables, such as $DEVICE, are read-write, and can be set using the SET command.
Special variables cannot take subscripts. Special variables cannot be incremented using the $INCREMENT function or killed using the KILL command. Special variables can be displayed using the WRITE, ZWRITE, ZZWRITE, or ZZDUMP commands, as described in Display (Write) Commands in the “Commands” chapter of Using ObjectScript.
Refer to the ObjectScript Reference for a list and detailed descriptions of the special variables.
Variable Typing and Conversion
Variables in ObjectScript are untyped — there are no specified data types. (This is also true of JavaScript, VBScript, and Document Data Base/JSON.) This means that you can assign a string value to a variable and, later on, assign a numeric value to the same variable. As an optimization, InterSystems IRIS may use different internal representations for strings, integers, numbers, and objects, but this is not visible to the application programmer. InterSystems IRIS automatically converts (or interprets) the value of a variable, based on the context in which it is used.
Some examples:
// set some variables
SET a = "This is a string"
SET b = "3 little pigs"
SET int = 22
SET num = 2.2
SET obj = ##class(Sample.Person).%New()
// Display them
WRITE "Here are the variables themselves: ",!
WRITE "a: ",a,!
WRITE "b: ",b,!
WRITE "int: ",int,!
WRITE "num: ",num,!
WRITE "obj: ",obj,!,!
// Now use them as other "types"
WRITE "Here are the numeric interpretation of",!
WRITE "a, b, and obj: ",!
WRITE "+a: ",+a,!
WRITE "+b: ",+b,!
WRITE "+obj: ",+obj,!,!
WRITE "Here are concatenations of int and num:",!
WRITE "Concatenating int: ","I found " _ int _ " apples.",!
WRITE "Concatenating num: ","There are " _ num _ " pounds per kilogram.",!
InterSystems IRIS converts values as follows:
From | To | Rules |
---|---|---|
Number | String | A string of characters that represents the numeric value is used, such as 2.2 for the variable num in the previous example. |
String | Number | Leading characters of the string are interpreted as a numeric literal, as described in the “String-to-Number Conversion” section of the “Operators and Expressions” chapter. For example, “–1.20abc” is interpreted as -1.2 and “abc123” is interpreted as 0. |
Object | Number | The internal object instance number of the given object reference is used. The value is an integer. |
Object | String | A string of the form n@cls is used, where n is the internal object instance number and cls is the class name of the given object. |
Number | Object | Not allowed. |
String | Object | Not allowed. |
Variable Declaration
Unlike other languages, you do not declare variables in ObjectScript. You can, however, use the #dim preprocessor directive as an aid to documenting code.
When writing code in Studio, you can use the #dim preprocessor directive. #dim provides information on the intended type of a variable. Studio uses this information for code completion with the Studio Assist feature. This information can also be used for documentation or to provide information to others who may view the code. (For more information on Studio Assist, see the section “Editor Options” in the “Setting Studio Options” chapter of Using Studio.)
The syntax forms of #dim are:
#dim VariableName As DataTypeName
#dim VariableName As List Of DataTypeName
#dim VariableName As Array Of DataTypeName
where VariableName is the variable for which you are naming a data type and DataTypeName specifies that data type. Studio provides a menu from which you can select the DataTypeName value.
#dim also allows you to specify an initial value for a variable, as in the following:
#dim President As %String = "Obama"