![]() |
![]() |
![]() |
![]() |
2 Defining and manipulating objects in AVS/Express
This chapter describes basic concepts useful for defining and manipulating AVS/Express objects to build applications and application components.
- Terms and concepts, Section 2.1
- Object hierarchy, Section 2.2
- Object characteristics, Section 2.3
- Defining primitive data objects, Section 2.4
- Defining groups, modules, and macros, Section 2.5
- Inheritance and the derivation hierarchy, Section 2.6
- Setting the reference mode of a group, module, or macro, Section 2.7
- Value expressions, Section 2.8
- Connecting objects by name, Section 2.9
- Defining combinations of properties and attributes, Section 2.10
- Defining link objects, Section 2.11
- Defining arrays of groups, modules, and macros, Section 2.12
- Instancing and de-instancing objects, Section 2.13
- Built-in functions, Section 2.14
An AVS/Express application is composed of a hierarchical collection of objects. AVS/Express enables you to create AVS/Express objects and connect them to form higher level objects and applications.
Each object is created from a base type that determines the low-level behavior of the object. Base types are grouped into six different categories based on the role that they play in defining applications:
A template is a module, macro, or group object located in a library. Because it resides in a library, AVS/Express does not execute any methods contained in the object. You use template objects to build your application.
AVS/Express offers many predefined templates, such as those for building your application's user interface. You can create your own templates and place them, too, in a library. All objects in a library are templates.
An instance is an active copy of a template. AVS/Express executes the methods of any objects that you place in the active application (that is, open in the NE application workspace), such as SingleWindowApp. You can create any number of instances from a single template.
AVS/Express is an object-oriented system that uses the prototype model. In the prototype model, you define types of objects in the same way that you define active objects themselves. The copy operation implements both the subclass operation and the construct operation. You also use the same syntax and methodology to edit active objects as you to do edit categories of objects. In the same way that a subclass inherits information from its superclass, an instance inherits information from its class.
To highlight the difference between these two models, AVS/Express uses the term template to describe what other object-oriented systems call class. This term more accurately describes the way that templates are used to "stamp out" new objects and reduces the confusion caused by existing meanings associated with the term class that conflict with how these concepts are implemented in AVS/Express.
Groups, modules, macros, and libraries can have subobjects, which themselves can have subobjects. This relationship of objects within objects is called the object hierarchy. AVS/Express has a single object hierarchy to which all objects belong.
The figure below illustrates a portion of the object hierarchy. Assume for this example that the current application is SingleWindowApp and that you have instanced two objects in it, UIfield and int1.
Here is how the objects appear in the Network Editor:
![]()
You use the following terms to refer to an object's position in the object hierarchy. (The table's examples refer to the previous figures.)
The object hierarchy includes other branches besides Libraries and Applications. Together, they define you development and execution environment. This environment is called your project. Each time you work with AVS/Express, you are working on a project. You can modify your environment by modifying the object hierarchy.
You can think of an object as having a number of characteristics: name, attributes, properties, and so forth. This section summarizes these characteristics.
Each object has an identifying name.
A name can consist of letters, numbers, and the special characters # and _. In the Network Editor, the character _ appears as a space. A name cannot comprise only numbers. Names are case sensitive.
A group, module, or macro object can be derived from one or more template objects. This object inherits the subobjects and behavior of the templates from which it is created and then has the opportunity to modify this behavior. Since each template may itself be derived from other objects, the list of all objects that contribute to the definition of a particular object forms a tree. This tree is called the derivation hierarchy.
For example, say that you instance a UIfield object. The new object's derivation hierarchy originates with the template object UIfield. UIfield is derived from the object UIvaluator which is derived from UIprimitive which is derived from UIgeom and UIwindow. The object directly inherits the characteristics of UIfield, but indirectly inherits all of the characteristics of all objects in its derivation hierarchy.
In non-prototyping object-oriented systems, this is called the class hierarchy of an object.
A C-style array declaration specifying the dimensions of a primitive data object, group, or macro can be made by setting the dimensions property for that object. By default (that is, without an array declaration), a primitive object has a single value. When the dimensions property is set, an object represents an array of primitive objects.
The dimensions property can be set to:
- A scalar value (for example, [1], [2], or [3][4]).
- A variable (for example, [dims], where dims is another int object).
- No value, leaving the array unbounded ( [] ).
The simplest array dimension declaration is a simple scalar value. For example:
If dimensions is set to reference another object (rather than being set to a constant value), the value of that object dynamically determines the dimensions of the array). For example:
In either case, whenever the value of dims is set, the foo array is dynamically redimensioned to reflect the value of foo. Note that caution should be used when using dynamic redimensioning, since the values in your array can be lost if they are incompatible with the new dimensions.
Objects can be declared as unbounded arrays by adding the dimensions property and including no value between the square braces (so the dimensions property has value "[]"). For example:
Such an object will automatically take on the dimensions of any array of values placed in foo. For example, if foo is set to equal {1,2,3,4,5}, the dimensions of foo will dynamically be set to [5], although the dimensions property is still seen to be unbounded when viewed in the Properties Editor.
Alternately, unbounded array objects may contain references to other objects and their dimensionality therefore set to be a function of other object's values. For example:
Note that strings, groups, modules, and macros can only be stored in a one-dimensional array.
For more information about arrays:
Properties and attributes both determine characteristics of the object on which they are set. You can set, examine, and change the values of both properties and attributes using either the Network Editor Properties Editor or directly through V. To find out more about setting properties and attributes, see:
A property is name-value association placed on an object. Properties names are usually defined by the system and relate to a specific aspect of object behavior. In V code, properties appear after the object name delimited by < and > characters.
Many properties control an object's appearance in the Network Editor, like the NEportLevels property which determines how ports are displayed for an object. Other system properties supply information for use with interfacing code to the system.
You cannot define properties as connections to other objects; they must be independent values.
An attribute is a boolean characteristic that you can apply to an object to modify its behavior. A fixed set of these characteristics are defined by AVS/Express.
For a complete listing of AVS/Express properties and attributes, see:
Objects like groups, modules, macros, and libraries can have subobjects. A group, module, or library's subobjects are displayed in a list form. A macro's subobjects appear as a network of connected objects.
An object can have either an explicit value or may have a value that is defined in terms of a connection to another object.
The way assignments and connections work differs between primitive data objects and groups, modules, and macros:
Primitive data objects are the simplest base types and are used to hold the raw system data. They are usually instanced as subobjects of a group or a module but can also be dropped into a macro as an independent piece of data. The following table lists the different types of data that are supported:
Each of the types above can represent either a scalar or a multi-dimensional array. Here are a few examples of different primitive data objects:
The ptr data type is used to store a pointer to a your data structure that may be passed from object to object. AVS/Express treats the entire data structure as a single entity; modules can be notified when the structure changes but cannot determine which pieces of the data have changed. AVS/Express cannot save and restore the value of a ptr object and does not communicate this ptr value between objects in different processes.
The byte, char, short, int, float, and double base types can be constrained by defining min/max/values subobjects for them:
- min - Establishes a minimum scalar integer or real value for the object
- max - Establishes a maximum scalar integer or real value for the object
- values - Defines a list (comma separated, within braces) of valid scalar integer or real values for the object
An attempt to set or get the value to or from an out-of-range value causes an error to be generated. Out of range set operations are not performed. get operations are clamped to the nearest valid value.
Since error checking is performed on set operations, errors on get values will occur when getting a value through a connection or when the min or max value has been changed after the value has been set.
Matching of objects prevent cases where the ranges do not overlap and reject these objects from being connected. Get/set value detection is only performed for scalar operands. Matching is performed for both scalars and arrays.
The boolean primitive base type is implicitly constrained, since the integer value of objects of this type can only be either 1 or 0.
Boolean data objects can connect to other data types that support an integer value, but this value will always be clamped to either 0 or 1 during the set or get operations as they go through the boolean object.
The enum primitive base type allows you to define objects whose value is restricted to one of a list of predefined values. The list of possible string or integer values (comma-separated, bounded by braces) is specified by defining the choices subobject for the enum object.
You can define a simple enum object, my_enum, in V by typing:
You can set the value of my_enum by assigning either a string or integer value:
Likewise, you can get its value as either an integer or a string:
However, if my_enum's data type is used explicitly in an expression, it will be treated as a string. The following V command:
produces the following output:
Primitive data objects can always serve either as the source or destination of a connection. When you are making simple connections between primitive data objects, since these connections respond symmetrically to read and write operations, there is not much difference between connecting object a to b and connecting b to a. There are two significant differences, however:
- An object that has a connection cannot be connected to another object without breaking that connection. If you intend to create a chain of three connected objects, you will only be able to extend this chain from the destination of the connection.
- The object that is connected to the other object loses its value when the connection is made. If the initial value of one object is important, make that object the destination of the connection.
For example, there are two unconnected objects, a and b:
Since object a has a default value, if it is the source of the connection, it loses its value and inherits the value of b (which in the case is not set):
If a new object c is introduced, it can only be connected to b in this case since a is already connected to b.
The group, module, and macro base types are very similar in how they behave but are used in different situations.
A group is used for an object that is a parameter to a module. It typically has primitive values and other groups as its subobjects. It is displayed in the Network Editor as a list. A typical group is the Field object:
A module is used to define an object that has methods and parameters as its subobjects. It is the object that manages the interface to C and C++ code. A typical module is the shell command module:
Modules and groups are very similar and in some cases their roles overlap. You can have one module be a parameter to another module.
A macro is used to define an object that has modules, other macros, and links as its subobjects. A macro is typically displayed as a graph (or network) of the objects and connections it contains (Network Display Mode):
In the Visualization Edition, you may not be able to open some macros, particularly lower-level objects embedded in other macros, in this manner. Where this is the case you will see only a group-like list display of the exported parameters from objects in the macro (Display List mode):
A group, module, or macro object inherits the definition of the template from which it was created, including subobjects, reference mode, array declaration, value expression, attributes, and properties.
For example, you create a template called color. Remember that to create a template you place the object in a library. Here is color, shown open:
The color object is created directly from the base type group and so it does not have any objects in its derivation hierarchy.
You then create an instance of color, called color1, shown here open and accompanied by its Object Info dialog:
Here's the underlying V code, which you can view in the VCP with the $print command:
color1's type is color, so color1 inherits color's definition: it too is a group and it too has subobjects red, green, and blue.
An object can have multiple types. This is called multiple inheritance or a merging of object templates.
For example, you create another template, called point:
You can create a new template called colorPoint, which inherits the definitions of both color and point. colorPoint is shown here, open and accompanied by its Object Info dialog:
In the Network Editor, you create an object with multiple inheritance by dragging down an object of the first type, then dragging down the second type with the Ctrl key pressed and dropping it onto the first object.
In V, when you create an object with multiple inheritance, you list all of the types you want to create separated by a "+" symbol:
If the objects being merged have similarly named subobjects, the subobjects themselves are merged. Where one of the subobjects has a characteristic that the other doesn't specify, AVS/Express uses the specified characteristic. Where both specify the same characteristics (for example, both specify an array declaration), AVS/Express resolves the conflict in favor of the type that is merged last (in V, that is the rightmost type in the type list).
Each object has a derivation hierarchy, indicating the object's chain of inheritance. At the top of an object's derivation hierarchy is the base type, such as group or macro.
Note: The derivation hierarchy is different from the object hierarchy. The derivation hierarchy describes how an object inherits its definition. The object hierarchy describes containment of objects within objects. See Section 2.2, Object hierarchy [page 2-4].
For example, you create an instance of ColorPoint:
ColorPoint1's derivation hierarchy looks like this:
You use the following terms for the derivation hierarchy. (The table's examples refer to the previous figure.)
You can modify a template object. These modifications ripple down the derivation hierarchy to derived templates and instances of the template. Changes ripple when the derived template or instance is reloaded into AVS/Express.
You can modify a derived template or instance, for example, by modifying or adding subobjects. The modifications are unaffected by subsequent modifications to the base template.
CAUTION: If you delete a subobject that is inherited by a derived template or instance, AVS/Express removes any objects from the derivation hierarchy that defined that subobject. For example:, if you delete the x subobject of the ColorPoint object above, the point template is removed from the derivation hierarchy of ColorPoint. It now looks like:
Since the reference mode behaves the same in each of the base types group, module, and macro, this section refers to the group base type but the description applies to module and macro as well.
By default, the group base type can serve only as the destination of a connection. Unlike primitive data objects which can always serve either as the source or destination of a connection, you must set the reference mode of a group in order to be able to have this object serve as the source of a connection.
The reference mode can be set by editing the ref_mode property via the Properties Editor in the Network Editor and by a symbol proceeding the object name in V. It has one of three values:
By-value reference mode is the default. Use this mode for groups that represent a real instance of the object. Methods are only executed and primitive data subobjects are only active within groups that are by-value.
Use by-reference reference mode when you want to define an object that behaves just like the object to which it is connected. Operations performed on the reference are transparently performed on the object at the end of the connection. A by-reference group has an "unset value" when it is not connected to anything. Any attempt to access the subobjects of a by-reference group that is not connected modifies the template of the group reference (see below for details).
Use by-pointer reference mode when you want to define a group that behaves like a pointer to another group. In order to operate on the group at the end of the connection, you must explicitly ask for the value of the pointer. If you have a method that wants to be notified when a by-pointer group changes, it is notified when connection changes, not when the subobjects of the group at the end of the connection change.
In effect, the difference between by-pointer and by-reference mode groups is that in a by-reference mode group, the subobjects of the group are virtually connected to the subobjects of the group's value. In the by-pointer mode group, there is no access to the subobjects of the value; the value of the connection is only the group object, not the group and its subobjects.
Since a by-reference group includes the subobjects of its value in its definition, it cannot be connected to its ancestor (that would include itself in its own list of subobjects). A by-pointer group can point to an ancestor object.
The subobjects of a by-pointer and a by-reference object are not active by themselves. Instead they define an object template that specifies the minimum information necessary to form a connection to this object. In other words, the group value that is connected to the group pointer or reference must match the template.
For the group value to match the template, it must have all the subobjects that the template has. Further, if any of the primitive data subobjects of the template have a value, the group value's subobject cannot have a conflicting value to match the template. For example, in the following figure the three groups on the left are defined by-value and the one on the right is by-reference. The by-reference group can only connect to the group value in the middle:
There is one case not described in this example. If the group template has a primitive data subobject that has a value and the group value has the necessary subobject but does not have any value set, this is considered a possible match and a connection is allowed. If the group value later has this subobject set to a value that conflicts with this subobject, the connection reference object is considered invalid. A method that requires this parameter to be valid will not run in this case.
When you are adding a method to the system, you indicate that you want your method to be called when certain object values change. This is called setting a notification on an object. When you set a notification on a group reference object, you are notified only when changes are made to subobjects in the group reference's value that are also in the group reference's template. In the example above, if you set a notification on group_ref, and it is connected to group_val2, you would be notified when sub_a and sub_b changed, but would not be notified when sub_c changed.
Since the group template is used for two purposes, both notifications and connection matching, you need ways to adjust your template to accommodate both uses:
- You can allow a connection to be made to a group value that does not match one or more subobjects of the template by setting the opt attribute on the unmatched subobjects of the template.
- You can set the nonotify attribute on a subobject of your group template so that the subobject will be used for connection matching, but you will not receive notifications when this subobject changes in the group value.
A value expression is a C-style expression, ranging in complexity from a constant, to an object reference, to a multioperand expression. An expression can return a scalar value or an array value of a particular dimensionality.
A value expression can either define a lasting connection or can simply perform a one-time modification of the value of the object. Making a connection by entering a value expression is the same as making this connection by visually connecting two icons.
The most common use of a value expression is to supply a value to a primitive data object. A scalar value expression can appear in other contexts, such as in the declaration of an array's dimension or the definition of a connection for a group with reference mode set to by-reference or by-pointer.
You can make connections between two objects using a value expression rather than making this connection by visually connecting two icons using the Network Editor. You do this by entering a value expression using the => operator. For example, by entering the value expression int1 into the int2 object, you are able to make this object connect to int1:
If you subsequently change the value of the int2 object, using the "=" operator, you modify the value of the object to which it is connected.
Because this connection is a read-write connection, if you enter
Notice that the value of both objects is changed and the connection is still preserved.
A scalar expression returns a scalar value. A scalar expression can include any of the tokens described in the table below. Several examples follow the table.
The <+>, <*>, and ! operands are read-write operations. Normally when an attempt is made to set the value of an expression, the expression is broken and the operands of the expression are left untouched. The <+> and <*> operands implement read-write addition and multiplication respectively. The first operand is modified to make the expression valid after the set value is performed.
The ! operation is always a read-write operation. An attempt to set the value of the ! operator to a non-zero value, results in setting the operand to 0. An attempt to set the ! operator to 0 sets the operand to 1.
An array expression returns an array value. An array expression can include any of the tokens described in the table below. Several examples follow the table.
For example, these two array value expressions each define an array with three elements:
{1,2,3}
{a, 4, b+2}
For example, assume that a1 and a2 are size-two arrays:The above array literal returns a three-by-two array. If a1 has the value {1,2} and a2 has the value {3,4}, the array literal specifies the value as:
For example, the following scalar expression (assume that x is a scalar object)
if assigned to a [2] array, is equivalent to the following array literal:
For example, if a1 is a [2][3] array, the following references all of a1's elements:
For example, if a1 is a [4][3] array, then the following returns a [3][2] array consisting of the elements in rows 0 through 2 and columns 1 and 2
is equivalent to the array literal
If a1 is an [4][3] array, this syntax
If a1 is an [3] array, this syntax
If a1 and a2 arrays of [2], this example
An array expression appears in an assignment or connection for an array object. AVS/Express can perform certain dimension conversions, when necessary.
Here are the rules for dimension conversion in an array value expression. The term "object" refers to the object to which the array expression is being assigned or connected:
- All array operands in the expression require the same number of dimensions and the same size in each dimension or the dimensions must be convertible. AVS/Express can either compress a pair of dimensions into one or expand a single dimension into two dimensions. For example, [3][2] can be compressed to [6] and [6] can be expanded to [3][2] but [3][2] cannot be directly converted to [2][3];
- If the object is a one-dimensional array with specified bounds, each operand in the expression must be either a scalar or an array the same size (that is, the same total number of elements) as the object. If an operand is a scalar, AVS/Express promotes it to an array the same size as the object.
- If the object is an array with unspecified bounds, each operand in the expression can be a scalar or an array. AVS/Express changes the object's array size to match the size and dimensions of the array operands.
- If the object is a multidimensional array, each operand must be either scalar or an array with the same number of dimensions and the same size in each dimension as the object. If the operand is scalar, AVS/Express promotes it to an array the same size as the object.
A primitive data object that has been instanced but not initialized has an unset value. Assigning an object with an empty expression returns it to the state of having an unset value.
AVS/Express performs C-style data-type conversion when necessary and if possible. In addition, AVS/Express can convert from char, byte, short, int, float and double to the string data type. For example:
When producing a string value, the "+" operator performs string concatenation. This example uses this feature to concatenate two simple strings:
Since a float or other primitive data object can be converted directly to a string, you can use this in the concatenation operation as well:
When you make a connection in the Network Editor, you define a read-write connection. Any change made to the value of the object that is connected to the other object changes the other object's value itself. (See Section 2.8, Value expressions [page 2-31] for an example).
When you define a connection to a math expression, you create a read-only connection to this math expression that is broken when an attempt is made to change the value of the object. This makes sense because most math expressions are not generally defined in the reverse direction. If you set the value of the expression "a + b", you do not know whether to change a, b, or both to continue to make this expression valid.
For example, you have the following objects connected through a math expression:
If you subsequently set the value of int2 to 100 using the "=" operator, it breaks the connection to int1 rather than modifying int:
You can create a read-only connection yourself by setting the rdonly property on the object that is the destination of the connection. Alternatively, you can construct a dummy math expression like: "a + 0". This technique is sometimes useful making transient one-way connections.
In most cases when you create a connection between two objects, you do so by visually connecting two ports. In certain places, however, you make a connection to an object by typing its name:
- in an object's value box, when specifying the target object of a connection or referring to an object in a value expression
- in the Properties Editor, when referring to an object while specifying an object's dimensions
This section describes the rules for describing a connection by name. Each object has a unique pathname that designates its location in the object hierarchy. For example:
Since all children of a particular object must have unique names, you are guaranteed that no two objects will share the same pathname. When referring to an object as part of a connection, you can always use the entire pathname of the object, but creating absolute references like this makes it difficult to relocate objects. Instead, you can omit any pathname entries that are shared by both the referencing and referenced object in the connection. For example, making a connection from
you can eliminate the common path entries and just use the pathname
To make a connection in the reverse order, you eliminate the common pathname entries:
The following examples illustrate coding a value expression for a primitive data object. But the rules apply to any place you code an object reference and for all kinds of objects, including groups.
A connection to a sibling or uncle object can be unqualified. AVS/Express is able to find the referenced object in the object hierarchy.
Simply type the object's name. Here are examples:
If the referencing object is higher in the object hierarchy than the referenced object, you supply the pathname entries that join the two objects.
- Object y connects to object x through an expression. The reference must fill in the objects in between grp1.grp2:
An ambiguous reference can occur when the referenced object's name appears at multiple levels in the object hierarchy. For example, you reference object x, but there exists both a sibling object x and an uncle object x.
By default, AVS/Express selects the object that is closest to the referencing object in terms of level in the object hierarchy.
To force AVS/Express to go up one level in the object hierarchy, enter the characters <- in the pathname. You can specify <- multiple times to go up multiple levels. Each <- must be followed by a dot to separate it from the next component of the pathname.
If you want an object with the pathname
using a pathname of "x" gets you the wrong x (you get Root.Applications.SingleWindowApp.x.x). Instead, you can qualify the pathname with
The two <- sequences cause the reference to skip the two levels of hierarchy between SingleWindowApp.x.x.a and SingleWindowApp.x.
You can force an object to only connect to a peer by preceding the name with a "." character. In this way, you can have an object
An array object can either have a single connection that points to an array object of the same dimensionality, or the array object can have a list of connections to either scalar objects or array objects that have one less dimension. For example, an array of size two is created from two scalars using
A scalar object can connect to a single element of an array object. These connections are not drawn in the Network Editor and must be entered by typing in the value of the scalar object. The syntax for this is value expression is
where array_object is the pathname of an array object that should have at least as many dimensions as there are []'s and each dim_expr is an expression producing an integer value. AVS/Express uses zero-based array indexing so 0 refers to the first value in that dimension. For example:
This same construct can connect an n dimensional array to a subsection of an array of less than n dimensions.
You can also connect an n dimensional array to a subset of another n dimensional array using the array range syntax. These connections also are not displayed in the Network Editor and must be entered into the value expression of the object. The syntax for one of these connections is
The referencing object is connected to a subregion of the array specified by array_object that includes values from the index min_value to and including max_value. min_value and max_value can be any expression that produces an integer value. This example connects a [2][2] array to a subregion of a [3][3] array:
In the previously illustrated example, the value of array2 is:
A single connection can mix range dimension specifications with simple value dimension specifications.
An array value can also connect directly to a scalar value itself. This implies an array of constant value.
A forward reference is a reference to an object that has not yet been defined. Forward references are allowed, but until the referenced object is defined, the expression returns a null value.
Caution: Since forward references are allowed, AVS/Express does not supply an error message if you reference an object does not exist. Use the $resolve V command to report unresolved references.
If you want to define a reference that will not be resolved by the time that AVS/Express attempts to resolve it (in other words, you want to suppress this error message), you can set the nres attribute on the object containing the unresolved references.
Recursive connections (or loops of connections) are not allowed. An error message is printed whenever you attempt to connect an object to itself either directly or through an expression, and the connection is disallowed.
Some objects in AVS/Express are defined solely to manage common combinations of properties and attributes so that V language definitions of objects can utilize a short-hand representation for referring to this group of attributes. In order to understand how these objects work, it is important to understand the general concepts behind the merge operation.
The merge operation that applies to groups, modules, and macros applies to other objects as well but it behaves somewhat differently.
In general, you can merge the definition of any template object into a compatible destination object. All information in the template object is added to the destination including properties, attributes, dimensions, data type, subobjects and value. When the destination object already has a conflicting definition of a particular piece of information, it is replaced by the new definition from the template object.
The objects involved in the merge operation must be compatible base types. You cannot merge a primitive data object into a group for example. If the objects involved in the operation are groups, modules, or macros, the template object is added to the derivation hierarchy of the destination object. If the object is not a group, module, or macro, the merge operation represents a one-time exchange of information. Future changes to the template are not propagated to the destination object as will happen with groups, modules, and macros.
The atts base type maintains properties and attributes. It can be merged into all different types of objects. When it is merged into a destination object, it simply copies the properties and attributes defined on it into the destination object. If the first type in a V construct is an attribute (such as the "read" attribute), the atts base type is implied. The following represent some standard AVS/Express V definitions of atts objects:
atts Port<NEportLevels=1>;
atts IPort<NEportLevels={1,0}>;
atts OPort<NEportLevels={0,2}>;
read+req+IPort2 Iparam; // here "atts" is implied.
These objects can be used when defining V descriptions of modules as short-hand for setting the NEportLevels property and the read, req attributes. You use these atts objects particularly when you are defining objects in V. For example:
AVS/Express defines a collection of these atts objects that you can use:
Link objects are used to route connections in as generic a way as possible. They can connect to any type of object and accept connections from any type of object and they ensure that both from and to connections are compatible in type. Link objects are commonly used in macros to perform one of the following functions:
- Route an input connection from multiple inputs inside the macro to a single output outside of the macro.
- Route an input from inside the macro to an output outside the macro so that the implementation of the macro can be changed without modifying references to the macro itself.
- Same as the above except for output connections.
- Gather multiple outputs from inside the macro and output them as a single array output.
There are two types of link objects:
If a connection is made first to a link object, all connections that are made from the link object must match the objects that are connected to it.
If the link object already is connected to another object, any new connections made to the link object must match the object to which the link is connected.
The link object uses the port colors of the objects either connected to it or to which it is connected.
An mlink can either combine a list of connections to scalars and output them as an array or can be connected to a single array input. In both cases, it outputs an array of values and should not be used to connect two scalars.
Here is an example of a macro using a link object to hide the implementation of the macro from outside users:
Here is an example of link objects used to fan out a single input to a list of inputs and fan in a list of outputs to a single output
:![]()
Objects created from the base type group, module, and macro can have dimension specifications to indicate that they are arrays. For simplicity, this section refers to the behavior of the group object but these operations apply equally well to modules and macros.
You define the dimensionality of an array of groups in the same way that you would define the dimensionality of a primitive data object with the exception that AVS/Express only supports one-dimensional arrays of groups. The behavior of an array of groups varies depending upon the reference mode of the object.
If the reference mode is set to by-reference (&) and the dimensions are set to indicate that this is an array, the object defines an array of references to groups. This object can accept either a single connection to an array of groups or a list of connections to individual groups. The matching rules for a scalar group reference apply for each object added to the list of references.
When defining an array of group references, it is often easier to leave the dimensions unspecified. This allows the Network Editor to add additional connections when connecting to scalars and allows the array of group references to be connected to an array of groups without concern for the dimensionality. If you need to access the array size in an AVS/Express object, you can use the array_size V function.
If you explicitly define the dimensions of your array of group references, you can only connect it to an array of groups that has the same dimensionality.
The following example defines an array of references to Field objects. The dimensionality of the array of references is left unspecified and it is connected to two scalar Field objects:
An array of group pointers defines an array of pointers to objects. It is specified in the same way as the array of group references (with the exception of the reference mode). For information on the difference between a pointer and a reference to a group
An array of groups that does not have the reference mode set maintains an explicit array of groups. The subobjects of an array of groups define a group template that is used to stamp out new array entries as its dimensionality changes. When the array dimensionality gets larger, new groups are created from the group template and added to the end of the list. As the array dimensionality gets smaller, the groups at the end of the list are destroyed.
This functionality is used to define a dynamic array of groups. If this array contains modules or macros that have underlying methods, these objects are instanced as they are created and de-instanced as they are destroyed.
In order to use this capability effectively, you often need to be able to make connections to and from the groups in the array and their subobjects.
There are several cases that are common:
- A subobject in each group in the array connects to the same object outside the array.
- A subobject in each group in the array connects to a corresponding object in a parallel array of groups or primitive data.
- An object from outside the array connects to a subobject of a specified group in the array.
- An object from outside the array treats the subobjects of each group in the array as an array.
In the template for the group array, you define a connection to a subobject outside of the array. Since each group in the array is stamped from the template, the subobject of each group is connected to the same value.
In the template for the group array, make a connection to an element of an array using the index_of function with the array. The index_of function returns an integer indicating its index in the group array. If the index_of function originates in the first element in the array, it returns 0. If it originates in the second element in the array, it returns 1, and so on. For example:
The object outside of the array can reference a subobject of the group with a constant index in its value expression. For example, to connect a value from outside of the array to the nspace subobject of the second element in the Field array (index 1) you place this value in the value expression:
In this example, you want to create an array of integers from the nspace subobjects of the Field array of the previous example. The array could be defined as
but this syntax does not increase the size of the nspace array when the Field array changes size. Instead, you simply use this syntax:
Since the object Field is an array of groups, not a scalar, this expression defines an array of nspace objects. Since nspace is an int, the result is an array of integers.
If the nspace subobject were itself a one-dimensional array, this defines a two-dimensional array (remember that AVS/Express only supports one-dimensional arrays of strings and groups so this does not work with these base types).
Usually, when you create an object as a child of an instanced object, it too becomes instanced. The system only executes methods in instanced objects. The Applications object in the system itself is instanced and therefore objects created in this hierarchy are instanced. There are two cases where this is not true:
- Objects of base type library or flibrary are never instanced (and consequently their children are also not instanced).
- Objects that have the instanced property set to 0 are not instanced.
When you set the instanced property on an object it can change the instanced state on the objects that are children of that object. If you set the state of the instanced property to 0 on an instanced object, all subobjects are de-instanced. This causes the de-instance methods of these objects to be called. If you set the state of the instanced property to 1 on a de-instanced object, it instances all the subobjects causing instance methods to be called.
The ScratchPad object in the File->New Applications menu of the Network Editor has the instanced property set to 0. This means that it, and any objects created in it, are not instanced. The ScratchPad object also has the property NEscratchPad set to 1 which means that objects dragged out of editable libraries are moved rather than copied.
A combination of these two features makes the ScratchPad useful for editing objects that interface to code. AVS/Express does not attempt to run methods that are not fully defined and makes it easier to replace the object into the library when you are finished.
A value expression can contain a built-in function. AVS/Express supplies several types of built-in functions: mathematical, logical, array, index_of, merge, name_of, str_array, and str_format.
- Arguments in a scalar expression - In a scalar value expression, each argument must itself be a scalar value expression.
- Arguments in an array expression - In an array expression, each argument can be a scalar value expression or an array value expression. A scalar value expression is promoted to an appropriately-sized array. Array expressions must resolve to arrays of an appropriate size and dimension for the defining object.
- Data type of arguments - The mathematical functions operate on any numeric data type, returning the appropriate data type, with any necessary data-type conversion.
- Equivalent operators - Several mathematical functions have equivalent operators, which you typically use instead. For example, you typically perform subtraction with the minus operator, not the sub function.
Logical and. Equivalent to arg1 & arg2 & ...
Logical or. Equivalent to arg1 | arg2 | ...
Logical exclusive or. Equivalent to ((arg1 ^ arg2) ^ ...)
The general rules for arguments are the same as those for the mathematical functions. See the previous section.
- Usage - Functions returning a single value can be used in a scalar or array expression. Functions returning an array can be used only in an array expression.
- Arguments - Arguments are typically array expressions, such as array literals or references to array objects. But they can be scalar expressions, in which case they are treated as one-element arrays.
- Presenting scalars as an array literal - With an array literal, you can present a set of scalar expressions as a single array, which you can then use as an argument in an array function like max_array.
-> float x[2][3] = {{1,2,3},{4,5,6}};
-> float y[2][2] = {{7,8},{9,10}};
-> int a => array_size(x);
-> $int a
6
-> float a[] => combine_array(x,y);
-> $get_array a
{{1,2,3,7,8},{4,5,6,9,10}}
-> $array_dims a
ndim=2 [2][5]
-> int a1[3]={1,2,3};
-> int a2[3]={5,6,7};
-> int a3[3]={8,9,10};
-> int c[] => concat_array(a1,a2,a3);
-> $get_array c
{1,2,3,5,6,7,8,9,10}
cache instructs AVS/Express to cache the result of the enclosed expression, so that the expression is recalculated only if the objects referenced in the expression have changed.
When an object is connected to an expression, AVS/Express by default recomputes an expression whenever the object's value is requested.
Caching involves a trade-off between the time required to recalculate an expression and the space required to cache the result.
For example, you define a group whose method creates a large array of float data, stored in subobject out. You also define an object called max and connect it to the maximum value in out:
group create_data {
float+write out[];
method_upd func = "create_data";
};
float max => max_array(out);
By default, every time you request max's value, AVS/Express recalculates the expression, even if out has not changed. To prevent this, use the cache function:
The cache function caches the result of an expression so that it is recomputed only when objects referenced by the expression have changed.
index_of returns the current index of an array of groups. You can use index_of in the value expression for a subobject of the array of groups.
merge defines an object that has all of the subobjects of object1 combined with the subobjects of object2.... etc. This is not a static merge like the "+" operator but continues to get changes made to its object arguments.
If subobjects of the same name exist in more than one object argument, the merge object uses the subobject found in the first object in the argument list.
-> group a {
-> int sub1 = 10, sub2 = 20;
-> };
-> group b {
-> int sub2 = 30, sub3 = 40;
-> };
-> group &c => merge(a,b);
-> c {
-> $print sub1
int sub1 = 10;
-> $print sub2
int sub2 = 20;
-> $print sub3
int sub3 = 40
name_of returns a string value containing the name of the object object. For example:
str_array returns an array of strings that are obtained by splitting up string_object into pieces delimited by the first character of the string value of the delimiter argument.
-> string a = "One;Two;Three";
-> string b[3] = str_array(a, ";");
-> $print b
string b[3] = {"One","Two","Three"};
str_format provides string formatting functionality like the standard C routine printf. The format parameter is a string defined just like the format parameter to printf. The format parameter contains two types of objects: characters that are placed directly in the string's value, and conversion specifications of the form:
The nth argument after format corresponds to the nth conversion specification in the format string. The data type of the argument is determined by the data type required by the conversion character.
If any one of the arguments after format is an array, this function provides an array of strings where the format string is applied to each value in the array individually. Otherwise, this function returns a scalar string value.
This function does not interpret the %n$ syntax of the printf function.
-> string v1 => str_format("number: %5d %s",3,"foobar");
-> $str v1
number: 3 foobar
-> string arr1[] => str_format("%10.3f",{1.2345,2.34,4.56});
-> string arr2[3] = arr1;
-> $print arr2
string arr2[3] = {" 1.234"," 2.340"," 4.560"};
switch returns one of its arguments depending on the value of index. If index is 1, switch returns the first argument. If index is 2, switch returns the second argument, and so on. If index is 0 or greater than the total number of arguments, a null value is returned.
When used as a primitive, switch's first subobject specifies the index; subsequent subobjects specify the arguments. For illustration of such usage, see the example below.
![]() |
![]() |
![]() |
![]() |
![]() |
Copyright © 2001 Advanced Visual Systems
Inc.
All rights reserved.