Skip to main content
Previous sectionNext section

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 Caché behavior to not generate an <UNDEFINED> error when referencing an undefined variable by setting the %SYSTEM.Process.Undefined() 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:

Each of these is used for a specific purpose and may have different scoping rules. Within a program you can use any category of variable in the same way (such as assigning values or passing them as function arguments.)

Local Variables

A local variable is a variable that is stored within the current Caché 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.

Caché 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 Caché Programming Orientation Guide. 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.

  • On Unicode systems, a local variable name 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.

Note:

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 Caché 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 an invalid variable name begins with an underscore character followed by a letter, the system generates a <_CALLBACK SYNTAX> error. (Note the underscore character within the error name.) For example, SET _abc = 123 or SET x = _abc. This is because Caché identifies these names as VISM control names, rather than local variable names.

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.

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.

Caché 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
Copy code to clipboard

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"
Copy code to clipboard

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 Caché Programming Orientation Guide.

    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 Caché 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 utility 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 specify 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"
  ZNSPACE "%SYS"
  DO ^GETPPGINFO("*")
Copy code to clipboard

^GETPPGINFO has the following syntax:

^GETPPGINFO("pdf","options","outfile")

The pdf argument can be a process Id or the * wildcard. The options argument can be a string containing any combination of the following: b (return values in bytes), Mnn (return only those process-private variables that use nn or more blocks); S (suppress screen display; used with outfile); T (display process totals only). The outfile argument 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 variables to an output file named ppgout. The S option suppresses screen display; the M500 option limits output to only process-private variables that use 500 or more blocks:

  ZNSPACE "%SYS"
  DO ^GETPPGINFO("*","SM500","/home/myspace/ppgout") 
Copy code to clipboard

Globals

A global is a special kind of variable that is automatically stored within the Caché 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.

Caché 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"
Copy code to clipboard

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 CACHESYS database, and are therefore preserved when you upgrade Caché. All other percent variables are reserved for system use according to the rules described in “Rules and Guidelines for Identifiers” in the Caché Programming Orientation Guide.

    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 Caché Globals.

  • Some global names are reserved for InterSystems use. For further details, refer to “Global Variable Names to Avoid” in the Caché Programming Orientation Guide.

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 Caché Globals.

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).

  • The maximum length of a subscript is 511 encoded bytes (the corresponding number of characters depends on the characters in the subscript and the current locale). Exceeding the maximum subscript length results in a <SUBSCRIPT> error. However, 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 Caché 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"
Copy code to clipboard

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 Caché 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 Caché 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)
Copy code to clipboard

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
Copy code to clipboard

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 Caché ObjectScript.

Refer to the Caché ObjectScript Reference for a list and detailed descriptions of the special variables.

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,!
Copy code to clipboard

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 special instance variable syntax i%PropertyName.

Variable Typing and Conversion

Variables in ObjectScript are untyped — there are no specified data types. (This is also true of JavaScript, VBScript, and Caché Basic.) 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, Caché may use different internal representations for strings, integers, numbers, and objects, but this is not visible to the application programmer. Caché 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.",!
Copy code to clipboard

Caché converts values as follows:

ObjectScript Type Conversion Rules
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.

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,!
Copy code to clipboard
Note:

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"
Copy code to clipboard

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),!
Copy code to clipboard

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, Caché 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
Copy code to clipboard

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
Copy code to clipboard

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"
Copy code to clipboard