Skip to main content

Indirection (@)

Enables you to include the syntax of a name, a pattern, a command argument, an array node, or a $TEXT argument indirectly through the value of an indirection operand.

Introduction to Indirection

The ObjectScript indirection operator (@) enables you to perform dynamic runtime substitution of part or all of a command line, a command, or a command argument. InterSystems IRIS® data platform performs the substitution before execution of the associated command.

Indirection is specified by the indirection operator (@) and, except for subscript indirection, takes the form:

@variable

where variable is the variable from which the substitution value is to be taken. The variable can be an array node. There are two steps to using the indirection operator:

  1. Assigning a value to variable, where the appropriate value depends on the intended context.

    Important:

    All variables referenced in the substitution value are public variables, even when used in a procedure.

  2. Including @variable in the applicable context — that is, as part or all of a command line, a command, or a command argument. Based on the context, there are five scenarios for the indirection operator, described on this page.

Here is a simple example, shown in a Terminal session.

USER>set y="B"
 
USER>set @y = 123
 
USER>write B
123

Limits and Alternatives

You should use indirection only in those cases where it offers a clear advantage. Indirection can have an impact on performance because InterSystems IRIS performs the required evaluation at runtime, rather than during the compile phase. Also, if you use complicated indirections, be sure to document your code clearly. Indirections can sometimes be difficult to decipher.

Although indirection can promote more economical and more generalized coding than would be otherwise available, it is never essential. You can always duplicate the effect of indirection by other means, such as by using the XECUTE command.

Indirection cannot be used with dot syntax. This is because dot syntax is parsed at compile time, not at runtime.

Important:

Do not use the indirection operator to get or set the value of an object property. If you do, the result may be an error, because this approach bypasses the property accessor methods (<PropertyName>Get and <PropertyName>Set). When you need to get or set the value of object properties in an indirect manner, use the $CLASSMETHOD, $METHOD, and $PROPERTY functions, which are designed for this purpose; see Dynamically Accessing Objects.

Scenario: Name Indirection

In name indirection, the indirection evaluates to a variable name, a line label, or a routine name. InterSystems IRIS substitutes the contents of variable for the expected name before executing the command.

Name indirection can only access public variables. For further details, see User-defined Code.

When you use indirection to reference a named variable, the value of the indirection must be a complete global or local variable name, including any necessary subscripts.

When you use indirection to reference a line label, the value of the indirection must be a syntactically valid line label. In the following example, InterSystems IRIS sets D to:

  • The value of the line label FIG if the value of N is 1.

  • The value of the line label GO if the value of N is 2.

  • The value of STOP in all other cases.

Later, InterSystems IRIS passes control to the label whose value was given to D.

B SET D = $SELECT(N = 1:"FIG",N = 2:"GO",1:"STOP")
 ; ...
LV GOTO @D

When you use indirection to reference a routine name, the value of the indirection must be a syntactically valid routine name. In the following example, name indirection is used on the DO command to supply the appropriate procedure name. At execution time, the contents of variable loc are substituted for the expected name:

Start
 READ !,"Enter choice (1, 2, or 3): ",num
 SET loc = "Choice"_num 
 DO @loc
 RETURN
Choice1()
 ; ...
Choice2()
 ; ...
Choice3()
 ; ...

Name indirection can substitute only a name value. The second SET command in the following example returns an error message because of the context. When evaluating the expression to the right of the equal sign, InterSystems IRIS interprets @var1 as an indirect reference to a variable name, not a numeric value.

 SET var1 = "5"
 SET x = @var1*6

You can recast the example to execute correctly as follows:

 SET var1 = "var2",var2 = 5
 SET x = @var1*6

Scenario: Pattern Indirection

In pattern indirection, the indirection operator replaces a pattern match. The value of the indirection must be a valid pattern. (See Pattern Match Operator.) Pattern indirection is especially useful when you want to select several possible patterns and then use them as a single pattern.

In the following example, indirection is used with pattern matching to check for a valid U.S. Postal (ZIP) code. Such codes can take either a five-digit (nnnnn) or a nine-digit (nnnnnnnnn) form.

The first SET command sets the pattern for the five-digit form. The second SET command sets the pattern for the nine-digit form. The second SET command is executed only if the postconditional expression ($LENGTH(zip) = 10) evaluates to TRUE (nonzero), which occurs only if the user inputs the nine digit form.

GetZip()
 SET pat = "5N"
 READ !,"Enter your ZIP code (5 or 9 digits): ",zip
 SET:($LENGTH(zip)=10) pat = "5N1""-""4N"
 IF zip'?@pat { 
   WRITE !,"Invalid ZIP code"
   DO GetZip()
 }

The use of indirection with pattern matching is a convenient way to localize the patterns used in an application. In this case, you could store the patterns in separate variables and then reference them with indirection during the actual pattern tests. (This is also an example of name indirection.) To port such an application, you would have to modify only the pattern variables themselves.

Scenario: Argument Indirection

In argument indirection, the indirection evaluates to one or more command arguments. By contrast, name indirection applies only to part of an argument.

To illustrate this difference, compare the following example with the example given under Name Indirection.

Start
 SET rout = "^Test1"
 READ !,"Enter choice (1, 2, or 3): ",num
 SET loc = "Choice"_num_rout 
 DO @loc
 QUIT

In this case, @loc is an example of argument indirection because it supplies the complete form of the argument (that is, label^routine). In the name indirection example, @loc is an example of name indirection because it supplies only part of the argument (the label name, whose entry point is assumed to be in the current, rather than a separate, routine).

In the following example, the second SET command is an example of name indirection (only part of the argument, the name of the variable), while the third SET command is an example of argument indirection (the entire argument).

 SET a = "var1",b = "var2 = 3*4"
 SET @a = 5*6
 SET @b
 WRITE "a = ",a,!
 WRITE "b = ",b,!

Scenario: Subscript Indirection

Subscript indirection is an extended form of name indirection. In subscript indirection, the value of the indirection must be the name of a local or global array node. Subscript indirection is syntactically different than the other forms of indirection. Subscript indirection uses two indirection operators in the following format:

 @array@(subscript) 

Assume that you have a global array called ^client in which the first-level node contains the client’s name, the second-level node contains the client’s street address, and the third-level node contains the client’s city, state, and ZIP code. To write out the three nodes for the first record in the array, you can use the following form of the WRITE command:

 WRITE !,^client(1),!,^client(1,1),!,^client(1,1,1)

When executed, this command might produce output similar to following:

John Jones
42 Arnold St.
Boston, MA 02745

To write out a range of records (say, the first 10), you could modify the code so that the WRITE is executed within a FOR loop. For example:

 FOR i = 1:1:10 {
 WRITE !,^client(i),!,^client(i,1),!,^client(i,1,1)
 }

As the FOR loop executes, the variable i is incremented by 1 and used to select the next record to be output.

While more generalized than the previous example, this is still very specialized code because it explicitly specifies both the array name and the number of records to output.

To transform this code into a more generalized form that would allow a user to list a range of records from any array (global or local) that stores name, street, and city information in three node levels, you could use subscript indirection as shown in the following example:

Start
 READ !,"Output Name, Street, and City info.",!
 READ !,"Name of array to access: ",name
 READ !,"Global or local (G or L): ",gl
 READ !,"Start with record number: ",start
 READ !,"End with record number: ",end
 IF (gl["L")!(gl["l") {SET array = name}
 ELSEIF (gl["G")!(gl["g") {SET array = "^"_name}
 SET x = 1,y = 1
 FOR i = start:1:end {DO Output}
 RETURN
Output()
 WRITE !,@array@(i)
 WRITE !,@array@(i,x)
 WRITE !,@array@(i,x,y)
 QUIT

The WRITE commands in the Output subroutine use subscript indirection to reference the requested array and the requested range of records.

In the evaluation of subscript indirection, if the instance of indirection refers to an unsubscripted global or local variable, the value of the indirection is the variable name and all characters to the right of the second Indirection operator, including the parentheses.

For a local variable, the maximum number of subscript levels is 255. Subscript indirection cannot reference more than 254 subscripts for a multidimensional object property. For a global variable, the maximum number of subscript levels depends on the subscript, and may be higher than 255, as described in Formal Rules about Globals. Attempting to use indirection to populate a local variable with more than 255 subscript levels results in a <SYNTAX> error.

A class parameter can be used as the base for subscript indirection in the same way that a local or global variable can be used as the base. For example, you can perform subscript indirection using a class parameter with the following syntax:

  SET @..#myparam@(x,y) = "stringval"

Scenario: $TEXT Argument Indirection

As its name implies, $TEXT argument indirection is allowed only in the context of a $TEXT function argument. The value of the indirection must be a valid $TEXT argument.

You use $TEXT argument indirection primarily as a convenience to avoid multiple forms of indirection that produce the same result. For example, if the local variable LINE contains the entry reference " START^MENU", you can use name indirection to the line label and to the routine name to obtain the text for the line, as follows:

 SET LINETEXT = $TEXT(@$PIECE(LINE,"^",1)^@$PIECE(LINE,"^",2))

You can use $TEXT argument indirection to produce the same result in a simpler manner, as follows:

 SET LINETEXT = $TEXT(@LINE)
FeedbackOpens in a new tab