Values

Expressions are evaluated into values at run-time (or live performance). There are two kinds of values:

A compound value is referred to using a handle (or pointer). So, the same compound value can be shared between variables or shared between nested data structures (see data structure).

This is important because a compound value v is a mutable data structure: you can change an element in the data structure and this does not change the value itself. It means that the variables referring to the value v will refer to the changed data structure. On the contrary, atomic values are immutable: you cannot change an atomic value, you can only build a new atomic value.

Functions can be used to combine values and build new ones. The programmer can define his or her own functions (see chapter Function), also having access to a large predefined Functions Library. The figure below shows a simple score excerpt employing a simple expression and value. The text score on the right declares four expressions to be sent to receivers “hr1-p” to “hr4-p” (harmonisers) whose final value is being converted from semi-tones to pitch-scale factor. This graphical representation shows their evaluation.

principe

In this example we are able to use the final values of the expression in the graphical display of the score by AscoGraph since the arguments of the expression are constant. So these expressions are recognized itself as constant and their value is computed when the score is loaded (a mechanism known as “constant propagation”). If a variable were to be used, the expression would stay intact in the visual representation to be evaluated at run-time. Variables will be discussed in section Variable.

Dynamic Typing

From a programming language perspective, Antescofo is a dynamically typed programming language: value types in Antescofo do not need to be explicitly specified; the type of values are checked during the performance and this can lead to an error at run-time.

When a wrong argument is provided to an operator or a predefined function, an error message is issued on the console and the returned value depends of the operators involved (often, the undef value). See section Dealing with Errors for useful hints on how to debug an augmented score.

Compound values are not necessarily homogeneous : for example, the first element of a vector (tab) can be an integer, the second a string and the third a boolean.

Note that each kind of value can be interpreted as a boolean or as a string. The string representation of a value is the string corresponding to an Antescofo program fragment that can be used to denote this value.

Checking the Type of a Value

Several predicates check if a value is of some type:

Value Comparison

Two values can always be compared using the relational operators

          <  <=  = !=  =>  >

and the @min and @max operators.

The comparison of two values of the same type is as expected: arithmetic comparison for integers and floats, lexicographic comparison for strings, etc. When an integer is compared against a float, the integer is first converted into the corresponding float. Otherwise, comparing two values of two different types is well defined but implementation dependent.

Defining a value in JSON format

Json (for JavaScript Object Notation) is an open-standard format that uses human-readable text to transmit data objects consisting of attribute–value pairs. It is the most common data format used for asynchronous browser/server communication.

The Json format can be used to defines Antescofo values using the keyword JSON:: in front of the json value definition. The Antescofo notation and the Json notation coincides, at the exception of map (dictionnaries). The correspondance between Json the value types and the Antescofo types is given by the following table:

Json value type Antescofo value type
bool bool
string string
number int or float
object map
array tab
null undef

The other Antescofo value types, like NIM or functions, cannot be written in Json.

For example (see Json for the format definition):

          $m := JSON:: { 
              "1" : 1, 
              "2" : 2, 
              "map" : { 
                  "a" : 0.10000000000000001, 
                  "b" : 1.00000000000000000, 
                  "pi" : 3.31415926534999983
              }, 
              "tab" : [
                  -1, 
                  -1.11109999999999998, 
                  "string", 
                  [
                      111, 
                      222, 
                      333
                  ], 
                  { 
                      "nested_map 1" : "1", 
                      "nested_map 2" : null, 
                      "nested_map 3" : [
                      ]
                  }, 
                  0
              ], 
              "trois" : "trois"
          }

defines the map

           MAP{ ("1", 1),
                ("2", 2),
                ("map", MAP{ ("a", 0.1), ("b", 1.0), ("pi", 3.31416) }),
                ("tab", TAB[-1,
                            -1.1111,
                            "string",
                            TAB[111, 222, 333],
                            MAP{ ("nested_map 1", "1"),
                                 ("nested_map 2", <undef>),
                                 ("nested_map 3", TAB[]) },
                            0]),
                ("trois", "trois") }

Several predefined functions are defined to handle the json format:



The various kind of values are reviewed in chapters Scalar Values and Data Structures. Antescofo is a high-order language, so Functions and Processes are also values, as well as Actors.

In the rest of this chapter, we review: