Struct
new to Analytica 7.0
Struct class
A Struct object defines a new atomic data type. A struct appears on a diagram with a shape that resembles a function shape, but with flat midsections on both the left and right.

After you have introduced a Struct, you can create instances of the struct. Each of those instances is atomic and immutable. The instance is atomic in the sense that Array Abstraction treats it as a single cell. It is immutable in the sense that once an instance is instantiated, it cannot be destructively altered.
A struct instance can have multiple member fields, each of which can have a different data type and dimensionality. For example, a single struct could have a scalar member, a 1-D member and a 2-D member, where the dimensions of the members are unrelated. The indexes of each member do not combine.
Note that a Struct is an Object, an instance of a struct is a Value.
Defining a Struct
To define a new data type, you create an object whose class is Struct. You can do this by first creating a user function object, and then in its Object window, changing its class to Struct.
Like a User-Defined Function (UDF), a Struct uses the Parameters attribute with precisely the same Function Parameter Qualifiers as a UDF. One example would be:
Struct MyDtype( a : atom ; b : Text [I] ; c: Number[J] )
This data type has three members -- a, b, and c. The a field can have any atomic data type, the b member must be text and is allowed to have the index I, and the c member must be a numeric and is allowed to have index J.
The default Definition of a Struct is Self. Sometimes it makes sense to include a more specialized definition -- see #Constructor customization below.
Instantiating a value
To create an instance of a Struct (an atomic value), you simply call the name of your struct as if it were a function from within an expression. In the previous example, that might be:
MyDtype( Category, Category_aliases, Category_IDs )
If there are extra dimensions in any of the values passed to the constructor parameters, Array Abstraction will kick in and you'll end up with multiple struct instances, each instance being one cell in the array-values result.
Accessing member values
Given an instance, use the Arrow operator to access member values. E.g.,
inst -> b
where inst was obtained by calling the Struct.
The left-hand side of the arrow can be a single instance, an array of instances, or even Null. The right-hand side of the arrow is the name of a member value.
Member functions
You can introduce your own member functions that are called using the syntax:
inst -> F(x,y)
The parameters are limited to be passed by values (e.g., no Index parameters). Keep in mind that the instance is immutable so these functions are not used in general to modify the internal state of the instance (although see the Section #Immutability below for exceptions).
To create your own member function, open up the Struct's diagram (as you would open up the diagram of a Module node) and drag a Function object to the diagram. In its Object window, set the parameters ensuring that the first parameter is declared as, e.g.,
Function F( Self : MyDtype atom ; param1 ; param2 )
The first parameter should be named Self and should have the Struct name as its data type and the atom qualifier. You can have zero or more additional parameters -- these are the ones passed to the function when it is called using the syntax inst → F(x,y). These parameters can have any data type qualifier, dimensionality declaration; however, at this time they cannot handle evaluation mode qualifiers or Object class qualifiers.
You can also introduce global variables that are "private" to the Struct and its member functions by adding normal variable nodes to the diagram. Note that these are contained in the Struct definition, not in each instance (to have a value that varies with each instance, you must use a member value.
Constructor customization
The member values of an instance are usually the parameter names that appear in the Parameter attribute of the struct (its Constructor's parameter names). However, in some use cases the constructor may change the member values, such as by adding new members, transforming the named members, or even removing members. These changes must be performed in the Definition of the constructor.
When you first view the Object window of a Struct, the Definition might not be visible (because altering the member values is somewhat esoteric). If you don't see it, use the Attribute visibility popup to make it visible.
Inside the constructor (and only in the constructor) the members can be assigned. For example:
Struct MyDType( a : atom ; b : Text [I] ; c : Number [J] ) Definition: Self -> creationTime := Today(true); Self -> c := c / Sum(C, J); Self
The final value is always Self whether or not your Definition actually returns Self, although it is clearer to do. Notice that in this example, it adds a new member value, creationTime, and changes the member value c to the normalized value.
When you change the member values in the constructor, you should consider whether you will ever assign values of your Struct to a definition or other expression attribute, or whether instances will even need to be saved directly in the model file. These cases require a text representation that is valid expression and which results in an equivalent instance. In the event that you alter the members, you may need to add a custom #ExpressionText member function that prints out a constructor call expression.
Enable comment auto-refresher