Difference between revisions of "Handles to Objects"

(IndexesOf(X))
(MetaIndex to LocalIndex, MetaVar to Var..Do, some hyperlinks)
 
Line 78: Line 78:
 
|}
 
|}
  
== MetaIndex..Do ==
+
== LocalIndex..Do ==
The construct, <code>MetaIndex i := indexExpr</code>, declares a local meta-index (see [[Local Indexes]]). This should generally be used in lieu of the Index <code>i := indexExpr</code> construct when «indexExpr» evaluates to a list of handles.
+
The construct, <code>[[LocalIndex]] i := indexExpr</code>, declares a local meta-index (see [[Local Indexes]]). This should generally be used in lieu of the Index <code>Index i := indexExpr</code> construct when «indexExpr» evaluates to a list of handles.
  
:<code>MetaIndex I := contains of Revenue_Module;</code>
+
:<code>[[LocalIndex]] I := [[Contains]] [[of]] Revenue_Module;</code>
:<code>Description of (I)</code>
+
:<code>[[Description]] [[of]] (I)</code>
  
See more at [[MetaIndex..Do]]
+
See more at [[Local..Do]]
  
 
== IndexesOf(X) ==
 
== IndexesOf(X) ==
Line 90: Line 90:
  
 
== Local Variables and Handles ==
 
== Local Variables and Handles ==
When you declare and use local variables that might hold handles, you should declare these local variables using [[MetaVar..Do]] or [[LocalAlias..Do]], rather than [[Var..Do]] or [[For..Do]]. When local variables hold handles, there are two semantic interpretations — the local variable could either be a storage location for a handle to an object, or it could act as an alias to the object. The [[MetaVar..Do]] or [[LocalAlias..Do]] declarations makes this distinction clear.
+
When you declare and use local variables that might hold handles, you should declare these local variables using [[Local..Do]] or [[LocalAlias..Do]], rather than [[Var..Do]] or [[For..Do]]. When local variables hold handles, there are two semantic interpretations — the local variable could either be a storage location for a handle to an object, or it could act as an alias to the object. The [[Local..Do]] or [[LocalAlias..Do]] declarations makes this distinction clear.
  
== MetaVar..Do ==
+
== Local..Do ==
The construct, <code>MetaVar temp := expr</code>, declares a local variable named «temp» that holds an atomic value or an array of values, some of which might be handles. When the value is a handle, the handle is treated as just another entity, whose datatype happens to be a handle. If you assign another handle or value to «temp», you simply change the contents of the local variable, and do not alter the object that the handle points to. Use this construct to manage collections of handles.
+
The construct, <code>Local temp := expr</code>, declares a local variable named «temp» that holds an atomic value or an array of values, some of which might be handles. When the value is a handle, the handle is treated as just another entity, whose datatype happens to be a handle. If you assign another handle or value to «temp», you simply change the contents of the local variable, and do not alter the object that the handle points to. Use this construct to manage collections of handles.
  
:<code>MetaVar hRevModule := Handle(Revenue_module);</code>
+
:<code>[[Local]] hRevModule := [[Handle]](Revenue_module);</code>
:<code>MetaVar hExpModule := Handle(Expense_module);</code>
+
:<code>[[Local]] hExpModule := [[Handle]](Expense_module);</code>
:<code>MetaIndex m := [hRevModule, hExpModule];</code>
+
:<code>[[Local]] m := [hRevModule, hExpModule];</code>
 
:<code>...</code>
 
:<code>...</code>
  
 
For the next example, suppose a global variable named <code>Hy</code> exists with a definition of <code>Handle(Y)</code>.  
 
For the next example, suppose a global variable named <code>Hy</code> exists with a definition of <code>Handle(Y)</code>.  
  
:<code>MetaVar a := Handle(X);</code>
+
:<code>[[Local]] a := [[Handle]](X);</code>
 
:<code>a := Hy</code>
 
:<code>a := Hy</code>
  
Line 109: Line 109:
 
When you need to iterate over a collection of handles, you can use, e.g.,
 
When you need to iterate over a collection of handles, you can use, e.g.,
  
:<code>MetaVar h[ ] := Contains of Revenue_module;</code>
+
:<code>[[Local]] h[ ] := [[Contains]] [[Of]] Revenue_module;</code>
 
+
You can assign non-handle values, such as numbers or text, to a local variable declared with [[MetaVar]]. When you do so, there is no difference between [[MetaVar..Do]] and [[Var..Do]].
+
  
 
== LocalAlias..Do ==
 
== LocalAlias..Do ==
The construct, <code>LocalAlias temp := expr</code>, evaluates «expr» and declares a local variable named «temp» that holds a single atomic value. When «expr» evaluates to a handle, the local variable identifier acts as an exact alias to the object pointed to by the handle.
+
The construct, <code>[[LocalAlias]] temp := expr</code>, evaluates «expr» and declares a local variable named «temp» that holds a single atomic value. When «expr» evaluates to a handle, the local variable identifier acts as an exact alias to the object pointed to by the handle.
  
:<code>LocalAlias r := Handle(Rate_input) Do r := r * 1.1</code>
+
:<code>[[LocalAlias]] r := [[Handle]](Rate_input) Do r := r * 1.1</code>
  
 
The preceding expression is functionally identical to<ref>This expression contains a side-effect to a global variable. Side-effects to global variables are only allowed in expressions or user-defined functions that are run directly from button scripts. This would cause an error if attempted from a variable’s definition.</ref>
 
The preceding expression is functionally identical to<ref>This expression contains a side-effect to a global variable. Side-effects to global variables are only allowed in expressions or user-defined functions that are run directly from button scripts. This would cause an error if attempted from a variable’s definition.</ref>
Line 124: Line 122:
 
For the next example, suppose a global variable named <code>Hy</code> exists with a definition of <code>Handle(Y)</code>.
 
For the next example, suppose a global variable named <code>Hy</code> exists with a definition of <code>Handle(Y)</code>.
  
:<code>LocalAlias a := Handle(X)</code>
+
:<code>[[LocalAlias]] a := [[Handle]](X)</code>
 
:<code>a := Hy</code>
 
:<code>a := Hy</code>
  
Line 135: Line 133:
 
When «expr» is an array of handles, then the body expression is iterated for each alias. The following expression increases the definition of every global variable within an indicated module to a value 1.1 times its initial value.
 
When «expr» is an array of handles, then the body expression is iterated for each alias. The following expression increases the definition of every global variable within an indicated module to a value 1.1 times its initial value.
  
:<code>LocalAlias x := Contains of Input_module;</code>
+
:<code>[[LocalAlias]] x := [[Contains]] [[of]] Input_module;</code>
 
:<code>x := x * 1.1</code>
 
:<code>x := x * 1.1</code>
  
Line 142: Line 140:
 
An easy mistake to make when using [[LocalAlias]] is to forget that «expr» is evaluated before the assignment. This feature allows you to compute the handle to the object that will be aliased, but it also means that you need to remember to surround an identifier with a call to [[Handle]]() when you just want a simple alias. If you write
 
An easy mistake to make when using [[LocalAlias]] is to forget that «expr» is evaluated before the assignment. This feature allows you to compute the handle to the object that will be aliased, but it also means that you need to remember to surround an identifier with a call to [[Handle]]() when you just want a simple alias. If you write
  
:<code>LocalAlias x := y</code>
+
:<code>[[LocalAlias]] x := y</code>
  
 
then this assigns to «x» the value of «y», not a handle to the object «y». If «y» happens to hold a handle to <code>z</code>, then «x» becomes an alias to <code>z</code>, not an alias to «y». To obtain an alias for «y», you must use  
 
then this assigns to «x» the value of «y», not a handle to the object «y». If «y» happens to hold a handle to <code>z</code>, then «x» becomes an alias to <code>z</code>, not an alias to «y». To obtain an alias for «y», you must use  
  
:<code>LocalAlias x := Handle(y);</code>
+
:<code>[[LocalAlias]] x := Handle(y);</code>
  
 
You can assign non-handle values, such as numbers and text, to a [[LocalAlias]] variable. When you do so, the local variable identifier serves as an alias for a single value, and is the same as  
 
You can assign non-handle values, such as numbers and text, to a [[LocalAlias]] variable. When you do so, the local variable identifier serves as an alias for a single value, and is the same as  
  
:<code>Var temp[] := expr;.</code>
+
:<code>Local temp[] := expr;</code>
  
== Conversions between MetaVar and LocalAlias ==
+
== Conversions between Local and LocalAlias ==
When writing expressions that manipulate handles in local variables, you may sometimes need to convert between [[MetaVar]] and [[LocalAlias]] semantics. When a [[MetaVar]] holds a handle, its value is an entity with the data type of handle. Since subtraction is not defined for a handle, the following expression is an error
+
When writing expressions that manipulate handles in local variables, you may sometimes need to convert between [[Local]] and [[LocalAlias]] semantics. When a [[Local]] holds a handle, its value is an entity with the data type of handle. Since subtraction is not defined for a handle, the following expression is an error
  
:<code>MetaVar hr := Handle(Revenue) Do hr - Expenses { Error }</code>
+
:<code>[[Local]] hr := [[Handle]](Revenue) Do hr - Expenses { Error }</code>
  
 
The expression is attempting to subtract the value of expenses (a number) from a handle. In this example, we need the [[LocalAlias]] semantics instead, so given <code>hr</code> we can convert using
 
The expression is attempting to subtract the value of expenses (a number) from a handle. In this example, we need the [[LocalAlias]] semantics instead, so given <code>hr</code> we can convert using
  
:<code>MetaVar hr := Handle(Revenue);</code>
+
:<code>[[Local]] hr := [[Handle]](Revenue);</code>
:<code>LocalAlias r := hr;</code>
+
:<code>[[LocalAlias]] r := hr;</code>
 
:<code>r - Expenses</code>
 
:<code>r - Expenses</code>
  
A <code>MetaVar</code> can also be dereferenced by using the [[Evaluate]]() function:  
+
A [[Local]] can also be dereferenced by using the [[Evaluate]]() function:  
  
:<code>MetaVar hr := Handle(Revenue) Do Evaluate(hr) - Expenses</code>
+
:<code>[[Local]] hr := [[Handle]](Revenue) Do [[Evaluate]](hr) - Expenses</code>
  
In the other direction, when a [[LocalAlias]], <code>r</code>, is an alias for another object and you need the handle to the object, use <code>Handle(r)</code>. It is legal to use the [[Handle]]() function on a local variable declared using [[LocalAlias]], but it is an error to apply the [[Handle]]() function to a local variable defined using [[MetaVar]]. This is because a local variable is not an object (it is just a name for a value), and since handles can only point to objects, there is no such thing as a handle to a local variable<ref>A local index is an object, so you can have a handle to a local index. The [[Index..Do]] and [[MetaIndex..Do]] constructs create an index object, along with a local variable name that has [[LocalAlias]] semantics for the index object.</ref>.
+
In the other direction, when a [[LocalAlias]], <code>r</code>, is an alias for another object and you need the handle to the object, use <code>[[Handle]](r)</code>. It is legal to use the [[Handle]]() function on a local variable declared using [[LocalAlias]], but it is an error to apply the [[Handle]]() function to a local variable defined using [[Local]]. This is because a local variable is not an object (it is just a name for a value), and since handles can only point to objects, there is no such thing as a handle to a local variable<ref>A local index is an object, so you can have a handle to a local index. The [[LocalIndex..Do]] and [[Index..Do]] constructs create an index object, along with a local variable name that has [[LocalAlias]] semantics for the index object.</ref>.
  
 
==Notes==
 
==Notes==
Line 183: Line 181:
 
* [[LocalAlias]]
 
* [[LocalAlias]]
 
* [[LocalAlias..Do]]
 
* [[LocalAlias..Do]]
* [[MetaVar]]
+
* [[Local..Do]]
* [[MetaVar..Do]]
+
* [[LocalIndex..Do]]
* [[Var]]
+
* [[Var..Do]]
+
* [[Index..Do]]
+
* [[MetaIndex..Do]]
+
 
</div>
 
</div>
  
  
 
<footer>References and Data Structures / {{PAGENAME}} / Dialog Functions</footer>
 
<footer>References and Data Structures / {{PAGENAME}} / Dialog Functions</footer>

Latest revision as of 00:11, 9 October 2021


A handle is a pointer to a variable, function, module, or other object. Using a handle lets you write variables or functions that work with the object itself, for example to access its attributes — instead of just its value which is what you usually get when you mention a variable by identifier in an expression.

Viewing handles

In a table result, a handle in an index or content cell usually shows the title of the object. If you select Show by identifier from the Object menu (or press Control+y), it toggles to show identifiers instead of titles (as it does in the node diagrams). If you double-click a cell containing a handle (title or identifier) it opens its Object window (as it does when you double-click a node in a diagram).

Attributes that contain handles

The attributes, inputs, outputs, and contains (the list of objects in a module) each consist of a list of handles to objects. The attribute isIn is a single handle to the module that contains this object — the inverse of contains.

List of variables: [v1, v2, ... vn]

If you define a variable as a list of variables, for example,

Variable A := [X, Y, Z]

the variable will have a self index that is a list of handles to those variables. In a table result view of A (or other variable that uses this index), the index A will usually show the titles of the variables. See List of variables for more. In an expression, the handles in the self index can be accessed using IndexValue(A). The main value of A (either mid value or a probabilistic view of A) contains the results of evaluating X, Y and Z.

Handle(o)

Returns a handle to an Analytica object, given its identifier «o».

Handle(Va1) →¨Va1

HandleFromIdentifier(text)

Returns a handle to global object (i.e., not a local variable or parameter), given its identifier as «text». See HandleFromIdentifier()

Variable B := 99
HandleFromIdentifier("B") → Va1

The dependency maintenance is unaware of the dependency on the object. Hence, any changes to the variable B above will not cause the result to recompute.

ListOfHandles(identifiers...)

Returns a list of handles to the specified Analytica objects, given their «identifiers». See ListOfHandles().

ListOfHandles(Va1, Va2, Va3) →¨ [Va1, Va2, Va3]

Indexes of Handles

MetaOnly attribute

When an index object is defined as a list of identifiers, the MetaOnly attribute controls whether it is treated as a general index or a meta-index. Meta-indexes are useful when reasoning about the structure or contents of the model itself. A general index evaluates the variables appearing in its definition to obtain its mid or sample value, and the values that are recognized by Subscript (i.e., a[i=x]), while a meta-index (having its MetaOnly attribute set to 1) does not evaluate the objects in the list. The following comparisons demonstrates the similarities and differences.

Constant E:= exp(1)
Variable X := -1
General Index Meta-Index
Index I0 := [E, X, Pi,True] Index I1 := [E, X, Pi,True]
MetaOnly of I0 := 0 {or not set} MetaOnly of I1 := 1
Variable A0 := Table(I0)(1, 2, 3, 4) Variable A1 := Table(I1)(1, 2, 3, 4)
IndexValue(I0) → [E, X, Pi, True] IndexValue(I1) → [E, X ,Pi, True]
Mid(I0) → 2.718, -1, 3.142,1] Mid(I1) → [E, X, Pi, True]
A0[I0 = Handle(E)] → 1 A1[I1 = Handle(E)] → 1
A0[I0 = Handle(True)] → 4 A1[I1 = Handle(True)] → 4
A0[I0 = E] → 1 A1[I1 = E] → Error:-2.718 not in I1
A0[I0 = -1] → 2 A1[I1 = -1] → Error:-1 not in I1
A0[I0 = True] → 4 A1[I1 = True] → Error:1 not in I1

LocalIndex..Do

The construct, LocalIndex i := indexExpr, declares a local meta-index (see Local Indexes). This should generally be used in lieu of the Index Index i := indexExpr construct when «indexExpr» evaluates to a list of handles.

LocalIndex I := Contains of Revenue_Module;
Description of (I)

See more at Local..Do

IndexesOf(X)

Returns the indexes of an array value as a list of handles. The first element of the list is null, rather than a handle, when «X» has an implicit dimension (also known as a null-index). See also IndexesOf.

Local Variables and Handles

When you declare and use local variables that might hold handles, you should declare these local variables using Local..Do or LocalAlias..Do, rather than Var..Do or For..Do. When local variables hold handles, there are two semantic interpretations — the local variable could either be a storage location for a handle to an object, or it could act as an alias to the object. The Local..Do or LocalAlias..Do declarations makes this distinction clear.

Local..Do

The construct, Local temp := expr, declares a local variable named «temp» that holds an atomic value or an array of values, some of which might be handles. When the value is a handle, the handle is treated as just another entity, whose datatype happens to be a handle. If you assign another handle or value to «temp», you simply change the contents of the local variable, and do not alter the object that the handle points to. Use this construct to manage collections of handles.

Local hRevModule := Handle(Revenue_module);
Local hExpModule := Handle(Expense_module);
Local m := [hRevModule, hExpModule];
...

For the next example, suppose a global variable named Hy exists with a definition of Handle(Y).

Local a := Handle(X);
a := Hy

Following the assignment, the local variable a contains a handle to Y. The variable X is unaltered. You should compare this to the same example using LocalAlias..Do in the following section.

When you need to iterate over a collection of handles, you can use, e.g.,

Local h[ ] := Contains Of Revenue_module;

LocalAlias..Do

The construct, LocalAlias temp := expr, evaluates «expr» and declares a local variable named «temp» that holds a single atomic value. When «expr» evaluates to a handle, the local variable identifier acts as an exact alias to the object pointed to by the handle.

LocalAlias r := Handle(Rate_input) Do r := r * 1.1

The preceding expression is functionally identical to[1]

Rate_input := Rate_input * 1.1

For the next example, suppose a global variable named Hy exists with a definition of Handle(Y).

LocalAlias a := Handle(X)
a := Hy

This expression is functionally identical to

X := Hy

The expression, if evaluated in a context where side-effects are permitted, would alter the definition of X. Following the assignment to a, the local variable a continues to be an alias to X. You should compare this to the same example for MetaVar..Do in the preceding section.

When «expr» is an array of handles, then the body expression is iterated for each alias. The following expression increases the definition of every global variable within an indicated module to a value 1.1 times its initial value.

LocalAlias x := Contains of Input_module;
x := x * 1.1

The rule for LocalAlias is that the result for the expressions using «temp» are identical to what you would get if you replaced every occurrence of «temp» within those expressions with the identifier for the variable pointed to by the handle, and then evaluated the expressions[2].

An easy mistake to make when using LocalAlias is to forget that «expr» is evaluated before the assignment. This feature allows you to compute the handle to the object that will be aliased, but it also means that you need to remember to surround an identifier with a call to Handle() when you just want a simple alias. If you write

LocalAlias x := y

then this assigns to «x» the value of «y», not a handle to the object «y». If «y» happens to hold a handle to z, then «x» becomes an alias to z, not an alias to «y». To obtain an alias for «y», you must use

LocalAlias x := Handle(y);

You can assign non-handle values, such as numbers and text, to a LocalAlias variable. When you do so, the local variable identifier serves as an alias for a single value, and is the same as

Local temp[] := expr;

Conversions between Local and LocalAlias

When writing expressions that manipulate handles in local variables, you may sometimes need to convert between Local and LocalAlias semantics. When a Local holds a handle, its value is an entity with the data type of handle. Since subtraction is not defined for a handle, the following expression is an error

Local hr := Handle(Revenue) Do hr - Expenses { Error }

The expression is attempting to subtract the value of expenses (a number) from a handle. In this example, we need the LocalAlias semantics instead, so given hr we can convert using

Local hr := Handle(Revenue);
LocalAlias r := hr;
r - Expenses

A Local can also be dereferenced by using the Evaluate() function:

Local hr := Handle(Revenue) Do Evaluate(hr) - Expenses

In the other direction, when a LocalAlias, r, is an alias for another object and you need the handle to the object, use Handle(r). It is legal to use the Handle() function on a local variable declared using LocalAlias, but it is an error to apply the Handle() function to a local variable defined using Local. This is because a local variable is not an object (it is just a name for a value), and since handles can only point to objects, there is no such thing as a handle to a local variable[3].

Notes

  1. This expression contains a side-effect to a global variable. Side-effects to global variables are only allowed in expressions or user-defined functions that are run directly from button scripts. This would cause an error if attempted from a variable’s definition.
  2. Not every object in Analytica lives in the global namespace (e.g., local indexes), so this rule doesn’t literally apply for handles to objects not in the global namespace. For these, we cannot replace the local name with an identifier since no global identifier exists for the object pointed to by the handle.
  3. A local index is an object, so you can have a handle to a local index. The LocalIndex..Do and Index..Do constructs create an index object, along with a local variable name that has LocalAlias semantics for the index object.

See Also


Comments


You are not allowed to post comments.