Reference Manual of LoI - Variables, Parameters and Typing

3.4 Variables, Parameters and Typing

Variables are represented by identifiers. They range over all basic and composed types. Variables which describe roles are handled in 3.6.3.
Variables have to be declared, before they can be used or modified. References to variables are constrained to the scope in which they have been declared.

3.4.1 Declaration

A variable is declared by a definition or an introduction. A definition has the form

<the variable given by its name> = <some expression>;

This has some consequences. The variable may now be used (inside the given scope), it has a value (the result of expression) and a type (which depends on the type of the expression). If another variable with the same name is already declared, the given definition just overrides (but does not change the value of) the other variable. All references in the scope to the name are now resolved by the variable just defined.
For function definitions it is also possible to use the following form (cf. 3.5.16 for the construction of user-defined functions):

<the variable given by its name> <parameters> = { <some statement> };

This is only syntactic sugar for

<the variable given by its name> = <parameters> => { <some statement> };

A variable can be introduced as part of a parameter list (cf. 3.4.5 and 3.9.2).The effects are similar to a definition (except that the value and type may not be clear immediately).
Finally, some variables (especially module names) are defined outside the current module. These have to be declared foreign in the module header:

foreign <a variable>, <a variable>,....., <a variable>

The type of these declared variables has to be matched with their foreign counterpart. Note, that there is only one global foreign namespace.

3.4.2 Modification

A variable which has been declared or introduced may be modified. A modification is either an assignment, a decrement, or an increment.

3.4.2.1 Assignment

An assignment has the form (cf. 3.5.12.3 for assigning values to components of arrays and cf. 3.5.14.3 for those of tuples)

<the name of the variable> : = <some expression>

The value of the variable will be changed to the result of the expression. Remark: The type of the variable may not be changed; it will be unified with the type of the expression.

3.4.2.2 Increment

An increment has the form

<a variable of type int>++

The given variable is incremented by one. If the maximal value is passed, an overflow may occur.

3.4.2.3 Decrement

A decrement has the form

<a variable of type int>- -

The given variable is decremented by one. If the minimal value is passed, an underflow may occur.

3.4.3 Usage

Variables may be used in expressions (cf. 3.5).

3.4.4 Scope

The scope of a variable is that part of the module, in which an reference in the form of the name of the variable will result in the variable itself.
The scope of a variable is limited to the block (and all subblocks), in which it has been declared. Furthermore, only backward references are allowed.

v 0 = 0;
v 0 := v 1;
v 1 = 1

The reference to v0 in the assignment is valid, but not that to v1 (considering that v1 is not declared elsewhere). This also means, that recursive references like v = v are not valid.
There is one exception of this rule: in functions definitions recursive references may be used (cf. 3.5.16.2).

3.4.5 Parameters

Parameters comprise either single identifier or a list of identifiers separated by commas and enclosed in parentheses:

< an identifier >
(< an identifier >,....,< an identifier >)

Parameters have the same properties as variables declared and used in the body (cf. 3.4).
The parameters-form can be used in module definitions ( cf. 3.3), function definitions (cf. 3.5.16.2), input/composed utterances (cf. 3.9.2 and 3.9.4) or type definitions (cf. 3.4.9). The scope of each parameter ranges in all cases except utterances over the whole entity. With regards to utterances the scope of a parameter is like a variable (cf. 3.4.4).

3.4.6 Typing

Variables and expressions are typed (This also includes the statements which pass or receive a value like return, input utterances, output utterances, throw and try). The type of a variable (and an expression) is either be determined by a type constraint (cf. 3.4.7) or the context, in which it is used. E.g.:

   R ? v::int

The type of the variable v is set by the constraint: it can only be int. The variable R has to be of type Role because of the requirements of an input utterance.
All values or variables for which it is not possible to determine their type are assumed to be of type Object.
A variable can not change its type - except it is redefined like in:

  v = 1;
  v = nil

3.4.7 Type Constraints

In some cases it is useful to constrain the type of a variable or an expression (e.g. documenting the interface of the interaction). Type constraints may be used for formal parameters of functions and in expressions. In both cases the syntax is similar:

<a variable> :: <a type expression>
<an expression> :: <a type expression>

The effect of this operator is that the type of the given expression or parameter has to be equal to that of the type expression. If the type expression is a function type or a parameterized type, that type has to be enclosed in parentheses.

3.4.8 Type Expressions

All possible type expressions are shown in this table:

Type (Schema) Description
void the empty type (cf. 3.5.2)
agent type of agent values (cf. 3.6.1)
aid type of agent identifiers (cf. 3.6.2)
constructor type of constructor values/markers (cf. 3.5.15)
bool type of boolean values (cf. 3.5.5)
module type of module values (cf. 3.5.10)
mutex type of mutex values (cf. 3.5.7)
int type of integers (cf. 3.5.3)
float type of floats (cf. 3.5.4)
object type of unspecified values (cf. 3.5.1)
char type of characters (cf. 3.5.6)
port type of port values (cf. 3.5.11)
role type of role values (cf. 3.6.3)
string array of characters (cf. 3.5.13)
thread type of thread values (cf. 3.8)
<identifier> a user defined type alias (cf. 3.4.9)
<identifier> <type expression> a user defined parameterized type (cf. 3.5.12)
{ <type expression> } an array type (cf. 3.5.12)
<type expression> => <type expression> a function type (cf. 3.5.16)
(<type expression>) grouping of a type
(<type expression>, <type expression>,....., <type expressions>) a tuple type /cf. 3.5.14)

Note, that if a component of a function type or parameterized type is another function type or parameterized type, that component has to be enclosed in parentheses.

3.4.9 Type Definitions

It is possible to define new types using primitive and composed types - including other defined types. Type definitions are statements (cf. 3.7.21). They are divided into simple type definitions (type aliases), parameterized types and type constructors. A simple type definition looks like:

typedef <a type identifier> = <a type expression>;

The given identifier will be bound to the given type expression. This new type can henceforth be used in type constraints. The scope of the type is restricted to all following statements in the block in which it is defined.
Note, that it is not possible to define a recursive type alias.
Parameterized types look like

 typedef <a type identifier> <parameters> =
         <a type expression>

The effect is similar to type aliases, except that you have to specify type expressions (cf. above) as arguments if you use the type. Cf. 3.4.5 for the format of parameters.
Note, that the parameters of the type may be constrained.
Examples for type aliases and parameterized types:

typedef   color = float;
typedef   pair component = (component, component);

Finally, we have type constructors. Type constructors are devices for defining concrete types. They take the following form

typedef <type identifier> <-
        <the name of the constructor> <a type expression>

The first identifier determines the name of the constructed type and the next one the name of the constructor. The type expression may contain references to the concrete type (or constructed type), which means rekursive definitions are possible for constructed types.
It is also possible to use parameters in type constructors:

typedef <the name of the type> <parameters> <-
        <the name of the constructor> <a type expression>
Examples for type constructors:

typedef simple <- Simple;
typedef pair <- Pair(pair, pair); 
typedef list <- Empty;
typedef list el <- Cons(el, list); 

The usage of type constructors is described in cf. 3.5.11; for deconstructing type constructors cf. 3.5.15.3.

Reference Manual of LoI - Variables, Parameters and Typing,
© 2000 by Gil Müller