Difference between revisions of "Handles to Objects"

m
(MetaIndex to LocalIndex, MetaVar to Var..Do, some hyperlinks)
 
(8 intermediate revisions by 2 users not shown)
Line 1: Line 1:
 
[[Category: Analytica User Guide]]
 
[[Category: Analytica User Guide]]
<breadcrumbs> Analytica User Guide > {{PAGENAME}}</breadcrumbs><br />
+
<breadcrumbs> Analytica User Guide > Procedural Programming > {{PAGENAME}}</breadcrumbs><br />
  
 
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.
 
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===
 
===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).  
+
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===
 
===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'''.
+
The attributes, <code>inputs, outputs</code>, and <code>contains</code> (the list of objects in a module) each consist of a list of handles to objects. The attribute <code>isIn</code> is a single handle to the module that contains this object — the inverse of <code>contains</code>.
  
 
==List of variables: [v1, v2, ... vn]==
 
==List of variables: [v1, v2, ... vn]==
Line 15: Line 15:
 
:<code>Variable A := [X, Y, Z]</code>
 
:<code>Variable A := [X, Y, Z]</code>
  
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” on page 175 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.
+
the variable will have a self index that is a list of handles to those variables. In a table result view of <code>A</code> (or other variable that uses this index), the index <code>A</code> will usually show the titles of the variables. See [[Functions_that_create_indexes#List_of_variables|List of variables]] for more. In an expression, the handles in the self index can be accessed using [[IndexValue]](A). The main value of <code>A</code> (either mid value or a probabilistic view of <code>A</code>) contains the results of evaluating <code>X</code>, <code>Y</code> and <code>Z</code>.
  
 
== Handle(o) ==
 
== Handle(o) ==
Returns a handle to an Analytica object, given its identifier <code>o</code>.  
+
Returns a handle to an Analytica object, given its identifier «o».  
  
:<code>Handle(Va1) ¨ Va1</code>
+
:<code>Handle(Va1) &rarr;¨Va1</code>
  
 
== HandleFromIdentifier(text) ==
 
== HandleFromIdentifier(text) ==
Returns a handle to global object (i.e., not a local variable or parameter), given its identifier as <code>text</code>.
+
Returns a handle to global object (i.e., not a local variable or parameter), given its identifier as «text». See [[HandleFromIdentifier]]()
  
 
:<code>Variable B := 99</code>
 
:<code>Variable B := 99</code>
:<code>HandleFromIdentifier("B") Va1</code>
+
:<code>HandleFromIdentifier("B") &rarr; Va1</code>
  
 
The dependency maintenance is unaware of the dependency on the object. Hence, any changes to the variable <code>B</code> above will not cause the result to recompute.
 
The dependency maintenance is unaware of the dependency on the object. Hence, any changes to the variable <code>B</code> above will not cause the result to recompute.
  
 
== ListOfHandles(identifiers...) ==
 
== ListOfHandles(identifiers...) ==
Returns a list of handles to the specified Analytica objects, given their identifiers.
+
Returns a list of handles to the specified Analytica objects, given their «identifiers». See [[ListOfHandles]]().
  
:<code>ListOfHandles(Va1,Va2,Va3) ¨ [Va1,Va2,Va3]</code>
+
:<code>ListOfHandles(Va1, Va2, Va3) &rarr;¨ [Va1, Va2, Va3]</code>
  
 
== Indexes of Handles ==
 
== Indexes of Handles ==
  
 
=== MetaOnly attribute ===
 
=== 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
+
When an index object is defined as a list of identifiers, the <code>MetaOnly</code> 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., [[Subscript-Slice_Operator|a[i=x]]]), while a meta-index (having its <code>MetaOnly</code> attribute set to 1) does not evaluate the objects in the list. The following comparisons demonstrates the similarities and differences.
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.
 
  
 
:<code>Constant E:= exp(1)</code>
 
:<code>Constant E:= exp(1)</code>
 
:<code>Variable X := -1</code>
 
:<code>Variable X := -1</code>
  
:{| border="1";
+
:{| class="wikitable"
 
! General Index
 
! General Index
 
! Meta-Index
 
! Meta-Index
 
|-
 
|-
| style="width:300px;" | Index I0 := [E,X,Pi,True]
+
| style="width:300px;" | <code>Index I0 := [E, X, Pi,True]</code>
| style="width:300px;" | Index I1 := [E,X,Pi,True]
+
| style="width:300px;" | <code>Index I1 := [E, X, Pi,True]</code>
 
|-
 
|-
|style="width:300px;" | MetaOnly of I0 := 0 {or not set}
+
|style="width:300px;" | <code>MetaOnly of I0 := 0 {or not set}</code>
|style="width:300px;" | MetaOnly of I1 := 1
+
|style="width:300px;" | <code>MetaOnly of I1 := 1</code>
 
|-
 
|-
|style="width:300px;" | Variable A0 := Table(I0)(1,2,3,4)
+
|style="width:300px;" | <code>Variable A0 := Table(I0)(1, 2, 3, 4)</code>
|style="width:300px;" | Variable A1 := Table(I1)(1,2,3,4)
+
|style="width:300px;" | <code>Variable A1 := Table(I1)(1, 2, 3, 4)</code>
 
|-
 
|-
|style="width:300px;" | IndexValue(I0) [E,X,Pi,True]
+
|style="width:300px;" | <code>IndexValue(I0) &rarr; [E, X, Pi, True]</code>
|style="width:300px;" |IndexValue(I1) [E,X,Pi,True]
+
|style="width:300px;" |<code>IndexValue(I1) &rarr; [E, X ,Pi, True]</code>
 
|-
 
|-
|style="width:300px;" |Mid(I0) 2.718,-1,3.142,1]
+
|style="width:300px;" |<code>Mid(I0) &rarr; 2.718, -1, 3.142,1]</code>
|style="width:300px;" |Mid(I1) [E,X,Pi,True]
+
|style="width:300px;" |<code>Mid(I1) &rarr; [E, X, Pi, True]</code>
 
|-
 
|-
|style="width:300px;" |A0[I0=Handle(E)] 1
+
|style="width:300px;" |<code>A0[I0 = Handle(E)] &rarr; 1</code>
|style="width:300px;"|A1[I1=Handle(E)] 1
+
|style="width:300px;"|<code>A1[I1 = Handle(E)] &rarr; 1</code>
 
|-
 
|-
|style="width:300px;" |A0[I0=Handle(True)] 4
+
|style="width:300px;" |<code>A0[I0 = Handle(True)] &rarr; 4</code>
|style="width:300px;" |A1[I1=Handle(True)] 4
+
|style="width:300px;" |<code>A1[I1 = Handle(True)] &rarr; 4</code>
 
|-
 
|-
|style="width:300px;" |A0[I0=E] 1
+
|style="width:300px;" |<code>A0[I0 = E] &rarr; 1</code>
|style="width:300px;" |A1[I1=E] Error:-2.718 not in I1
+
|style="width:300px;" |<code>A1[I1 = E] &rarr; Error:-2.718 not in I1</code>
 
|-
 
|-
|style="width:300px;" |A0[I0=-1] 2
+
|style="width:300px;" |<code>A0[I0 = -1] &rarr; 2</code>
|style="width:300px;" |A1[I1=-1] Error:-1 not in I1
+
|style="width:300px;" |<code>A1[I1 = -1] &rarr; Error:-1 not in I1</code>
 
|-
 
|-
|style="width:300px;" |A0[I0=True] 4
+
|style="width:300px;" |<code>A0[I0 = True] &rarr; 4</code>
|style="width:300px;" |A1[I1=True] Error:1 not in I1
+
|style="width:300px;" |<code>A1[I1 = True] &rarr; Error:1 not in I1</code>
 
|}
 
|}
  
== MetaIndex..Do ==
+
== LocalIndex..Do ==
The construct, <code>MetaIndex i := indexExpr</code>, declares a local meta-index (see [http://wiki.analytica.com/index.php?title=Local_Indexes Local indexes]). This should generally be used in lieu of the Index <code>i := indexExpr</code> construct when <code>indexExpr</code> 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 [[Local..Do]]
  
 
== IndexesOf(X) ==
 
== 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 <code>X</code> has an '''''implicit dimension''''' (also known as a '''''null-index''''').
+
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 ==
 
== Local Variables and Handles ==
When you declare and use local variables that might hold handles, you should declare these local variables using <code>MetaVar..Do or LocalAlias..Do</code>, rather than <code>Var..Do or For..Do</code>. 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 <code>Meta-Var..Do</code> or <code>LocalAlias..Do</code> 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 <code>temp</code> 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>
  
Following the assignment, the local variable <code>a</code> contains a handle to <code>Y</code>. The variable <code>X</code> is unaltered. You should compare this to the same example using <code>LocalAlias..Do</code> in the following section.
+
Following the assignment, the local variable <code>a</code> contains a handle to <code>Y</code>. The variable <code>X</code> 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.,
 
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 <code>MetaVar</code>. When you do so, there is no difference between <code>MetaVar..Do</code> and <code>Var..Do</code>.
 
  
 
== LocalAlias..Do ==
 
== LocalAlias..Do ==
The construct, <code>LocalAlias temp := expr</code>, evaluates <code>expr</code> and declares a local variable named <code>temp</code> that holds a single atomic value. When <code>expr</code> 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 123: 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 130: Line 129:
 
:<code>X := Hy</code>
 
:<code>X := Hy</code>
  
The expression, if evaluated in a context where side-effects are permitted, would alter the definition of <code>X</code>. Following the assignment to <code>a</code>, the local variable <code>a</code> continues to be an alias to <code>X</code>. You should compare this to the same example for <code>MetaVar..Do</code> in the preceding section.
+
The expression, if evaluated in a context where side-effects are permitted, would alter the definition of <code>X</code>. Following the assignment to <code>a</code>, the local variable <code>a</code> continues to be an alias to <code>X</code>. You should compare this to the same example for [[MetaVar..Do]] in the preceding section.
  
When <code>expr</code> 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>
  
The rule for <code>LocalAlias</code> is that the result for the expressions using <code>temp</code> are identical to what you would get if you replaced every occurrence of <code>temp</code> within those expressions with the identifier for the variable pointed to by the handle, and then evaluated the expressions<ref>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.</ref>.
+
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<ref>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.</ref>.
  
An easy mistake to make when using <code>LocalAlias</code> is to forget that <code>expr</code> 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 <code>Handle()</code> when you
+
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
just want a simple alias. If you write
 
  
:<code>LocalAlias x := y</code>
+
:<code>[[LocalAlias]] x := y</code>
  
then this assigns to <code>x</code> the value of <code>y</code>, not a handle to the object <code>y</code>. If <code>y</code> happens to hold a handle to <code>z</code>, then <code>x</code> becomes an alias to <code>z</code>, not an alias to <code>y</code>. To obtain an alias for <code>y</code>, 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 <code>LocalAlias</code> 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 <code>MetaVar</code> and <code>LocalAlias</code> semantics. When a <code>MetaVar</code> holds a handle, its value is an entity with the data type of handle. Since subtraction is not defined for a handle, the
+
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
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 <code>LocalAlias</code> 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 [http://wiki.analytica.com/index.php?title=Evaluate Evaluate]() function:
+
A [[Local]] can also be dereferenced by using the [[Evaluate]]() function:  
 +
 
 +
:<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 [[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==
 +
<references/>
  
:<code>MetaVar hr := Handle(Revenue) Do Evaluate(hr) - Expenses</code>
+
== See Also ==
 +
<div style="column-count:2;-moz-column-count:2;-webkit-column-count:2">
 +
* [[Handle]]
 +
* [[Objects and Values]]
 +
* [[ListOfHandles]]
 +
* [[HandleFromIdentifier]]
 +
* [[Handle Functions]]
 +
* [[Local Indexes]]
 +
* [[IndexesOf]]
 +
* [[LocalAlias]]
 +
* [[LocalAlias..Do]]
 +
* [[Local..Do]]
 +
* [[LocalIndex..Do]]
 +
</div>
  
In the other direction, when a <code>LocalAlias</code>, <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 <code>Handle()</code> function on a local variable declared using <code>LocalAlias</code>, but it is an error to apply the <code>Handle()</code> function to a local variable defined using <code>MetaVar</code>. 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>.
 
  
 
<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.