Objects and Values
There are two primary types of entities that comprise and are manipulated by Analytica models: Objects and Values. Understanding this simple distinction can help you understand several of the other language features and concepts in Analytica.
An Analytica value is essentially data. A value can be an intelligent array or an atomic value. An intelligent array is a collection of atomic values. The result of any calculation is a value. Anything passed as a parameter to a function or an operator is a value. Values can be stored in various ways, and are the entities manipulated through calculation.
An Analytica object is an entity that has a class, a name, and set of attribute values. Each attribute value associates a value with a particular attribute, so that an object typically contains several values. For example, a (global) variable, which you often see as a rounded rectangle on an influence diagram, is an object that usually has values associated with the attributes Title, Description, Units, Definition, (mid-)Value, ProbValue (aka. Sample value), Domain and Check among others. In addition, Class and Identifier are also attributes.
The word entity is not a term we use when referring to Analytica concepts. I use it here to help with the description. The terms value and object are specific terms we use within Analytica, and each have each have a precise meaning as described in this article. Both of these words are used in other ways in English and in computer science, so take note that we are using these here to refer to Analytica values and Analytica objects, as opposed to other common meanings of each of those words.
Value can take subdivided into these subtypes (among others)
Atomic values form the cells of arrays, but they may also stand by themselves as values. For example, the result of 1+2 is the atomic value 3, which is not an array. The Title attribute of any object is an atomic text value. We use the term "atomic value", or just "atom", to distinguish from an array.
A array is a rectangular (or hyper-rectangular) collection of "cells", where each cell contains an atomic value. Arrays can have between 1 and 24 dimensions (or between 1 and 15 dimensions in 32-bit Analytica). Each dimension is associated with an index, with each dimension associated with a different index. An index, by the way is an object. There is one exception -- during computation, one dimension of an array can contain an implicit index. A list is a 1-D array where the only dimensions is an implicit dimension. Lists are used to define indexes. See also Atomic function parameters and Atomic..Do.
An Analytica object is an entity that has a Class, an Identifier (or name), and several other attribute values. The class and identifier are in fact attributes themselves. Most objects are in the global namespace, and each object in the global namespace must have a unique identifier. Some objects, most notably local indexes, are not in the global namespace, and don't need to have a unique identifier.
Objects can be sub-divided into the following subtypes (among others)
- Global variables
- Built-in functions
- User-Defined Functions
- Model objects
- Text nodes
- FormNodes (user input and output nodes)
- Alias nodes
- Graph style templates
- Local Indexes
- Domain Indexes
The Object Window is used to view an object, and from that window you can directly see the various attribute values contained within the object. The Object Window shows you a subset of these values. From the Typescript Window, you can use the Profile command so see all the attribute values in an object.
What about COM Objects?
Are COM objects actually objects, as the name implies? The answer is that they are not Analytica objects, as identified above, although they do have similar characteristics in many ways. For example, whereas Analytica objects have attribute values, COM objects have properties. As mentioned earlier, the word object is used in many ways in computer science, and the term COM objects was created outside the context of Analytica. When you call COMCreateObject, a thing called a COM object is instantiated somewhere in your computer's memory (it can even be in the memory of a remote computer), but the result from COMCreateObject is a "moniker" or "pointer" to that object, which is a type of atomic value that is used to reference that thing. This pointer is an Analytica value.
Suppose you define a variable,
A, to be a call to COMCreateObject. Its result is a pointer to that COM object. If you then define variable
B to be
A, the pointer is copied, but there is still only a single COM object. Now both
B point to the same COM object.
A Handle is an indirect referent to an Analytica object, and a Reference is an indirect referent to an Analytica value. These are the two fundamental forms of indirection referents. You can think of an indirect referent as a pointer. For example, an object exists somewhere in memory. There is only one copy of this object. But you might want to refer to this object -- that is the role of a handle. Similarly, a value exists somewhere in memory. You may want to refer to that value without making a copy of it -- a Reference allows you to do this. When you create multiple copies of a handle, the object itself is not copies -- they all point to the same object -- you end up with several handles to the same object.
Because Analytica is a functional language with referential transparency, a reference does not allow you to change the contents of a value. Any time you make a change to a value, a new copy must be made. However, the useful thing about a reference is that it is itself an atomic value. So even though it might "point" to an array, it acts as an atom for Array Abstraction.
Locals are identifies in expressions that act as names for either values or objects. There are a couple different types of locals:
- Local Indexes
- Local values, declared using MetaVar..Do or Var..Do, or passed as value parameters to a User-Defined Function.
Local indexes create an index object, which can then serve as the dimension on an array. The identifier of the local index is therefore a name that can be used to refer to the index object. Local indexes to not live in the global namespace, so they do not need to have a unique identifier. When you declare a local index, you can specify the object name explicitly, and it does not have to be the same as the local name. This is done using this syntax
Index I / "Name" := expr;
Within the lexical scope of
I, you can refer to this index object by
I, but the name of the object is actually
A LocalAlias declares a name for an object, that can be used within a local lexical expression scope. Hence, in the following declarations,
K can be used as names for other pre-existing objects.
LocalAlias I := Data.Row;
LocalAlias J := Handle(Va1);
LocalAlias K := Contains of ModelDetailsModule;
In the last example,
Contains of ModelDetailsModule is a list of handles, but within the lexical scope of
K will name only one of these objects at a time. The body expression -- that expression in the lexical scope of
K, will be evaluated once for each object in
Contains of ModelDetailsModule.
Most other local variables, declared using MetaVar..Do, Var..Do, or For..Do, are alias to values. It is important to note that local variables are not Analytica objects, whereas global variables (those that show on influence diagrams) are Analytica objects. Again -- local variables declare a name for a value. There is only one value -- there is not a separate Mid-Value or Sample-Value. The value is computed and set when the variable is declared (or assigned to), and after that, the evaluation mode has no relevance.
- The domain of possible values
- Values in Object Window
- Evaluation Modes
- Objects and Their Attributes
- Attrib of Obj
- Classes of variables and other objects
- Change class of an object
- COM objects
- Object window
- Object menu
- Object Manipulation Typescript Commands
- Handles to Objects