TOC PREV NEXT INDEX

Core AVS/Express and the Object Manager


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.

This chapter discusses:

2.1 Terms and concepts
2.1.1 Objects

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.

2.1.2 Base types

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:

Category
Base types
Description
library
library, flibrary
Holds collections of objects that you use to build your application
macro
macro, application
Holds combinations of modules, macros, and connections
module
module
Holds parameters and methods to implement objects that interface to C or C++ code
parameters
byte, char, short, int, float, double, string, ptr, prim, group, enum
Maintain data usually operated on by methods. Data can be scalar, array, and hierarchical
method
omethod, cmethod, cxxmethod
Objects that interface directly to a C function or C++ method
link
link, mlink
Objects that route connections, often into or out of a macro or application object

2.1.3 Templates

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.

2.1.4 Instances

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.

2.1.5 Object-oriented paradigm

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.

2.2 Object hierarchy
Description

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:

Terminology

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.)

Term
Description and examples
Parent
The object immediately above an object.
Example:  x's parent is UIfield. UIfield's parent is SingleWindowApp. SingleWindowApp's parent is Applications. Applications' parent is Root.
Ancestor
Any object above an object.
Example:  x's ancestors are UIfield, SingleWindowApp, Applications, and Root.
Immediate subobject
(or child)
Any object immediately below an object.
Example:  SingleWindowApp's immediate subobjects are UIfield and int1. UIfield's immediate subobjects include x, y, and others.
Subobject
Any object below an object, at any level.
Example:  SingleWindowApp's subobjects are UIfield, int1, x, y, and the other subobjects of UIfield.
Sibling
(or peer)
Any object with the same parent as an object.
Example:  UIfield and int1 are siblings. x, y, and the other immediate subobjects of UIfield are siblings.

Projects and your development environment

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.

For details about working with projects, see Chapter 4, Projects, libraries, and processes."
2.3 Object characteristics

You can think of an object as having a number of characteristics: name, attributes, properties, and so forth. This section summarizes these characteristics.

2.3.1 Name

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.

2.3.2 Derivation hierarchy

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.

See Section 2.6, Inheritance and the derivation hierarchy  [page 2-21].
2.3.3 Declaring the dimensions of an array

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:

Scalar dimensions

The simplest array dimension declaration is a simple scalar value. For example:


Or in V code:

int foo[3];
Constant dimensions

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:


Or in V code:

int foo[dims];

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.

Unbounded 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:


Or in V code:

int foo[];

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:

See, Section 3.4.7, Viewing and setting an object's array declaration  [page 3-42]
See Section 2.4, Defining primitive data objects  [page 2-14].
See Section 2.12, Defining arrays of groups, modules, and macros  [page 2-55].
2.3.4 Properties and attributes

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:

The chapter on working with the Network Editor in the AVS/Express User's Guide.
Chapter 3, V and the V Command Processor
Properties

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.

Attributes

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:

Appendix 1, Properties, attributes, primitives, and functions
2.3.5 Subobjects

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.

For more information on subobjects, see Section 1.5, AVS/Express object hierarchy  [page 1-20]
2.3.6 Values and connections

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:

Section 2.8, Value expressions  [page 2-31]
Section 2.4, Defining primitive data objects  [page 2-14]
Section 2.7, Setting the reference mode of a group, module, or macro  [page 2-27]
2.4 Defining primitive data objects

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:
Primitive
Description
boolean
byte
char
double
enum
float
int
short
string
ptr
prim
Boolean integer
One-byte integer
Single character
Double-precision float
Enumerated data type
Single-precision float
Integer
Short integer
A NULL-terminated character string
Pointer to user data structure
Object with unset data type used for any one of the above

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:


2.4.1 Using ptr 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.

2.4.2 Constraining primitive data objects

The byte, char, short, int, float, and double base types can be constrained by defining min/max/values subobjects for them:

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.

Examples
-> int foo {
-> min = 3;
-> max = 5;
-> };
-> // the following produces an error
-> foo = 7;
-> int foo {
-> values = {0,1,2};
-> };
-> // the following produces an error
-> foo = 3;
2.4.2.1 boolean base type

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.

2.4.2.2 enum base type

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:

-> enum my_enum {
-> choices = {"choice a", "choice b"};
-> };

You can set the value of my_enum by assigning either a string or integer value:

// these have the same result
-> my_enum = 0;
-> my_enum = "choice a";

Likewise, you can get its value as either an integer or a string:

-> $str my_enum
choice a
-> $int my_num
0

However, if my_enum's data type is used explicitly in an expression, it will be treated as a string. The following V command:

-> string a => "prints as " + my_enum;
-> $str a

produces the following output:

prints as choice a
2.4.3 Connection rules for primitive data objects

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:

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.

2.5 Defining groups, modules, and macros

The group, module, and macro base types are very similar in how they behave but are used in different situations.

Groups

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:


Modules

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.

Macros

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):


2.6 Inheritance and the derivation hierarchy
2.6.1 Single and multiple inheritance
Single inheritance

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:

$print color1
color color1;

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.

Multiple inheritance

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:

color+point colorPoint;

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).

2.6.2 Derivation hierarchy
Description

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:

ColorPoint ColorPoint1;

ColorPoint1's derivation hierarchy looks like this:


Terminology

You use the following terms for the derivation hierarchy. (The table's examples refer to the previous figure.)

Term
Description and examples
Base type
The base type at the top of an object's derivation hierarchy.
Example:  ColorPoint1's base type is group.
Base template
The object immediately above an object in the derivation hierarchy.
Example:  ColorPoint1's base template is ColorPoint. ColorPoint has two base templates, color and point.
Derived template
A template created from another template object. This is similar to the object-oriented term subclass.
Example:  ColorPoint is a derived template of color and point.
Instance
An active copy of a template object.
Example:  ColorPoint1 is an instance of ColorPoint.

2.6.3 Modifications to templates, derived templates, and instances
Modifying a template

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.

Modifying a derived template or instance

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:

2.7 Setting the reference mode of a group, module, or macro

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:
Reference mode
Symbol
Description
By-value
By-reference
By-pointer
^
&
*
Maintains its own value
References the subobjects of another object
Is a pointer to an object that must be explicitly dereferenced to access the subobjects

By-value reference mode

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.

By-reference reference mode

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).

By-pointer reference mode

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.

Group templates

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.

Template connection matching

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.

Notifications of group references

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.

Relaxing the template using the opt and nonotify attributes

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:

2.8 Value expressions

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.

Making connections/setting values

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


and then press Return you get


Notice that the value of both objects is changed and the connection is still preserved.


2.8.1 Scalar expressions

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.

Scalar token
Description
Constant
A C-style numeric or string constant.
Un-escaped string literal
A string constant that does not need quote characters to be escaped with the \ character. It begins with the sequence <" and ends with the sequence ">.
Object reference
A reference to another object.
Several considerations apply to referencing an object, such as when and how to qualify the object's name and how to reference a subobject of a group array.
Array element
A reference to an element of an array object. The reference has the form:
object[index]...
index specifies the array element's subscript in a given dimension. index can be a scalar expression returning an integer value. AVS/Express uses zero-based indexing, so 0 refers to the first value in an array dimension.
Operator
A numeric, character, or logical, or comparison operator:
+ Addition
- Subtraction
* Multiplication
/ Division
% Modulo
-expr Unary minus
+ String concatenation
& Bitwise AND
| Bitwise OR
^ Bitwise XOR
&& Logical AND (left-to-right evaluation)
|| Logical OR (left-to-right evaluation)
~ One's complement
== Equal to
!= Not equal to
< Less than
> Greater than
<= Less than or equal to
>= Greater than or equal to
Note: The above comparison operators work for array operands in addition to scalars. When array operands are given, they return an array of integers indicating the value of an item-by-item comparison of the objects.
<+> Read-write addition
<*> Read-write multiplication
! Read-write negation
For more details of the above read-write operands, see Read-write operands on page 2-35.
Note: All operators follow C's order of precedence. Use parentheses to override the default order.
Built-in functions
An AVS/Express built-in function.
Null
A null value, specified by typing nothing after the assignment/connection operator. This is particularly useful for breaking a connection in a V statement.

Read-write operands

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.

For example:

-> int b = 2;
-> int a => b <+> 3;
-> a = 8;
-> $print b
int b = 5;

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.

2.8.1.1 Examples of scalar expressions

345 Numeric literal
3.45 Numeric literal
3.45e1; Numeric literal
"AVS" String litera l
<""hi world""> Unescaped string literal (in this case specifying "hi world")
x Object reference
{1,2,3} Array
a1[2] Array element
c2 * (y + z) Multioperand expression
pow(c3,.5) Function (in this case, effectively a square root)
2.8.2 Array value expression

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.

Array token
Description/Examples
Array literal
An array literal consisting of a comma-separated set of scalar expressions (such as constants and object references) or array expressions. An array literal has the following form:
{expr, ...}
If you specify array expressions, each array requires the same number of dimensions and size in each dimension.
Scalar value expression
Any item that is valid in a scalar value expression. AVS/Express promotes the scalar value to an array the size of the object.
Full array
A reference to all of the elements in an array object. The reference has the following form:
object_name  
Several considerations apply to referencing an object, such as when and how to qualify the object's name and how to reference a subobject of a group array.
Array section
A reference to a subset of elements in an array object. An array section has the following form:
object_name[start:end]...
start and end specify the array section's starting and ending subscripts in a given dimension. start and end are scalar expressions. AVS/Express uses zero-based indexing, so 0 refers to the first element in a dimension.
Reduced dimensionality array
You can reference a one or more dimensions of a multi-dimensional array with the form:
array_object[expr][]
The sequence [] is used to indicate which dimensions you want to preserve. An expression indicates which dimensions you want to remove. If fewer dimensions are specified than defined in the array, AVS/Express automatically fills in the remaining dimensions with [].
Mix of scalar and array operands
AVS/Express performs the indicated operations on each element of each array.
Built-in function
AVS/Express' built-in functions can operate on an array.

Examples of array literal

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:

{a1, a2, {5, 6}}

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:

{{1,2}, {3,4}, {5,6}}
Example of scalar expression

For example, the following scalar expression (assume that x is a scalar object)

x+2

if assigned to a [2] array, is equivalent to the following array literal:

{x+2, x+2}
Example of full array

For example, if a1 is a [2][3] array, the following references all of a1's elements:

a1
Example of array section

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

a1[0:2][1:2];

2*a1*a2

is equivalent to the array literal

{2*a1[0]*a2[0], 2*a1[1]*a2[1]}
Examples of reduced dimensionality array

If a1 is an [4][3] array, this syntax

a1[][0]

is equivalent to

{a1[0][0], a1[1][0], a1[2][0], a1[3][0]}

With the same a1, the syntax

a1[0][]

is equivalent to

{a1[0][0], a1[0][1], a1[0][2]}
Example of scalar/array expression

If a1 is an [3] array, this syntax

a1 * 3

is equivalent to

{a1[0] * 3, a1[1] * 3, a1[2] * 3}
Example of built-in function

If a1 and a2 arrays of [2], this example

pow(a1, a2)

is equivalent to

{pow(a1[0],a2[0]), pow(a1[1],a2[2])}
2.8.3 Dimension conversion in an array expression

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:

2.8.4 Uninitialized objects have a null value

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.

2.8.5 Data-type conversion

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:


2.8.6 Concatenating strings

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:


2.8.7 Read-only connections

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.

2.9 Connecting objects by name

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:

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:

Root.Applications.SingleWindowApp.grp1.a

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

Root.Applications.SingleWindowApp.grp1.a

to

Root.Applications.SingleWindowApp.b

you can eliminate the common path entries and just use the pathname

b

To make a connection in the reverse order, you eliminate the common pathname entries:

grp1.a

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.

2.9.1 Connecting to a peer by name

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:


2.9.2 Connecting to a peer of an ancestor

2.9.3 Connecting to a subobject of a peer

If the referencing object is higher in the object hierarchy than the referenced object, you supply the pathname entries that join the two objects.

Here is an example:


2.9.4 Resolving an ambiguous reference

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

Root.Applications.SingleWindowApp.x.x.a

to reference the object

Root.Applications.SingleWindowApp.x

using a pathname of "x" gets you the wrong x (you get Root.Applications.SingleWindowApp.x.x). Instead, you can qualify the pathname with

<-.<-.x;

The two <- sequences cause the reference to skip the two levels of hierarchy between SingleWindowApp.x.x.a and SingleWindowApp.x.

2.9.5 Limiting connections to one-level

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

SingleWindowApp.x.a

reference the object

SingleWindowApp.x.x

using the pathname

.x
2.9.6 Connections to and from arrays

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


int scalar_a, scalar_b;
int array[] => {scalar_a, scalar_b};

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

array_object[dim1_expr]...[dimn_expr]

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

array_object[min_value:max_value]

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:

{{1,2},{4,5}}

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.

2.9.7 Forward references

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.

Suppressing unresolved errors

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.

2.9.8 Recursive 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.

2.10 Defining combinations of properties and attributes

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.

2.10.1 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.

2.10.2 Maintaining properties and attributes

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:

int+IPort foo;
Field+Iparam bar;

AVS/Express defines a collection of these atts objects that you can use:

atts object name
Definitions
Port
sets NEportLevels = 1
IPort
sets NEportLevels = {1,0}
OPort
sets NEportLevels = {0,1}
Port2
sets NEportLevels = 2
IPort2
sets NEportLevels = {2,0}
OPort2
sets NEportLevels = {0,2}
Port3
sets NEportLevels=3
IPort3
sets NEportLevels={3,0}
OPort3
sets NEportLevels={0,3}
Iparam
sets NEportLevels={2,0}, read, req
Oparam
sets NEportLevels={0,2}, write, nonotify

2.11 Defining link objects

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:

There are two types of link objects:

Base type
Description
link
Makes links between scalar objects
mlink
Makes links between array objects

Rules for both link and mlink connections

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.

Rules for mlink connections

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
:

2.12 Defining arrays of groups, modules, and macros

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.

2.12.1 Arrays of group references

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:


2.12.2 Array of group pointers

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

See Section 2.7, Setting the reference mode of a group, module, or macro  [page 2-27]
2.12.3 Array of group values

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.

Here is a simple array of groups as presented by the Network Editor:

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:

2.12.3.1 Subobjects in the array connect to a common subobject

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.

2.12.3.2 Subobjects in the array connect to a parallel array

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:


2.12.3.3 An object outside of the array connects to a single element in the array

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:

Field[1].nspace
2.12.3.4 Treat the subobjects of the group array as an array itself

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

{Field[0].nspace, Field[1].nspace, Field[2].nspace}

but this syntax does not increase the size of the nspace array when the Field array changes size. Instead, you simply use this syntax:

Field.nspace

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).

2.13 Instancing and de-instancing objects

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:

2.13.1 Setting the instanced property

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.

2.13.2 Using ScratchPad

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.

2.14 Built-in functions

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.

2.14.1 Mathematical functions
Mathematical function
Description
abs(arg)
acos(arg)
add(arg1...)
asin(arg)
atan(arg)
Absolute value of arg
Arc cosine of arg, expressed in radians
Addition. Equivalent to arg1 + arg2 + ...
Arc sine of arg, expressed in radians
Arc tan of arg, expressed in radians
cos(arg)
cosh(arg)
divide(arg1...)
exp(arg)
log(arg)
Cosine of arg, expressed in radians
Hyperbolic cosine of arg, expressed in radians
Division. Equivalent to arg1 / arg2 / ...
e raised to the power of arg
Natural logarithm of arg
log10(arg)
modulo(arg1...)
multiply(arg1...)
pow(arg1, arg2)
sin(arg)
Base 10 logarithm of arg
Modulo. Equivalent to arg1 % arg2 % ...
Multiplication. Equivalent to arg1 * arg2 * ...
arg1 raised to the power of arg2
Sine of arg, expressed in radians
sinh(arg)
sqrt(arg)
sub(arg1...)
tan(arg)
tanh(arg)
Hyperbolic sine of arg, expressed in radians
Square root of arg
Subraction. Equivalent to arg1 - arg2 - ...
Tan of arg, expressed in radians
Hyperbolic tan of arg, expressed in radians
rand(range, [ seed ])
A random scalar or array with values between 0 and range. If no seed argument is specified, it gives a different random array for each object (i.e., the object id is used as the seed). If seed is specified, it is used as the seed for the random numbers.

Note the following:

2.14.2 Logical functions
Logical function
Description

and(arg1...)
or(arg1...)
xor(arg1...)

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.

2.14.3 Array functions
Array function
Description
array_size(arg)
Returns the total number of elements in arg.
array_dims(arg)
Returns the dimensions of the array specified in arg.
combine_array(arg1...)
Combines arg1, arg2, ... The arrays must have the same number of dimensions, n, and the same size in the first n-1 dimensions. The function returns an n-dimension array, where the size in the first n-1 dimensions is the same as the source arrays, and the size of the nth dimension is the sum of the sizes of the source arrays' nth dimension.
concat_array(arg1, ....
Concatenates arg1, arg2, ... to create one array with dimensions equal to the sum of dimensions of all the arrays.
index_of(arg)
Returns the index of the current object in the array of groups specified by arg. This function must be used by an object that is in a group in the array of groups specified by arg. It is used to create connections between objects in two parallel arrays of groups.
init_array(size,start,end)
Returns a one-dimensional array of size elements that range in ascending order from start to end.
magnitude(arg)
Returns the magnitude (square root of sum of squares) of each column in arg. The function returns an n-1 dimension array, where n is the number of dimensions in arg.
max_array(arg)
max_array(arg, f, v)
Returns (in a one-dimensional array) the maximum value found in each column in the array arg.
If the array has null values, you can include two additional arguments, setting flag f to 1 to indicate that the function should ignore null values, and v to the number that represents a null value. By default, f is 0, meaning that the function operates on all array values.
min_array(arg)
min_array(arg, f, v)
Like max_array, but returns the minimum value of each column in array arg.
prod(arg1...)
Returns the product of all of the elements in arg1, arg2, ...
sum(arg1...)
Returns the sum of all of the elements in arg1, arg2, ...
sum_array(arg1)
Creates a new array, each element of which is a sum of all the previous elements in the original array.


Note the following:

Examples
-> int x = 10;
-> int y = 20;
-> int z = 3;
-> int a = max_array ({x, y, z});
-> $int a
20
-> 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}
-> float a[] => magnitude(x);
-> $get_array a
{3.74166,8.77496}
-> float a => max_array(x);
-> $real a
6.000000
-> float a => prod(x,y)
-> $real a
3628800.000000
int a[4]={1,2,3,4};
int b[] => sum_array(a);
$get_array b
{1,3,6,10}
2.14.4 cache function
cache (expression)

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:

float max => cache(max_array(out));

The cache function caches the result of an expression so that it is recomputed only when objects referenced by the expression have changed.

2.14.5 index_of function
index_of (group_array_object)

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.

For example:

group foo[3] {
int a=> index_of(foo);
};
!foo[0] {
$int a
0
};
!foo[1] {
$int a
1
};
2.14.6 merge function
merge (object1, object2, ...)

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.

For example:

-> 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
2.14.7 name_of function
name_of(object)

name_of returns a string value containing the name of the object object. For example:

-> group grp1 {
-> string str1 => name_of(<-);
-> $str str1
grp1
2.14.8 str_array function
str_array(string_object, delimiter)

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.

For example:

-> string a = "One;Two;Three";
-> string b[3] = str_array(a, ";");
-> $print b
string b[3] = {"One","Two","Three"};
2.14.9 str_format function
str_format(format, arg1, arg2, ..., argn)

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:

%[field width].[precision][conversion character]

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.

Data type
Conversion characters
integer
d, i, o, u, x, X
real
e, E, f, g, G
string
s
pointer
p

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.

Example

For example:

-> 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"};
2.14.10 switch function
switch(index,arg1,arg2...)

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.

//
// Use switch as a primitive.
// Start by defining an index variable.
//
int i;

//
// Define a switch.
//
switch x {
int index => i;
int val1 = 10;
int val2 = 20;
};

// Define an integer and connect it to switch x.
//
int result => x;

TOC PREV NEXT INDEX

Copyright © 2001 Advanced Visual Systems Inc.
All rights reserved.