Variables

A variable refers to a value. A variable is identified by its name. A variable has no type. The type is hold by the value. Thus, a variable can hold values of different types. For example the following code is valid:

x = 2;
x = "a";

Variables are always assigned by reference and have global or local visibility. The default value for a variable is nil.

Global variables

Global variables are attached to modules. They are available from all the functions declared in the same module. Global variables do not need to be declared before use. The default value of a global variable is nil. It’s the default visibility for implicitly declared variables.

Example:

i = 15; // Declare and assign global variable i
println(i, j); // Use variable i and j. J is implicitly declared

Local variables

A local variable is only available in the block of code defining that variable and in blocks enclosed in its defining block. These blocks are called the scope of the variable. Local is the default visibility for:

  • Parameters of functions

  • Loop variables used in a for statement

  • Loop variables used in an iterated function call

  • Loop variables used in an iterated assignment

  • Exception variable used in a try/catch clause

  • Resource variable used in a with statement

Users can also introduce local variables with the local keyword. Introducing a local variable when a global variable with the same name is already defined will cause this name to be associated to the local variable in its visibility scope. Introducing a local variable when a local variable with the same name is already defined and visible from the current code block will throw an error. Thus, only one local variable with the same name is allowed for any scope in the program.

For example the following code will throw the error Variable 'i' already defined.:

function foo(i) {
    for [i in 0...10] print(i);
}

On the contrary the following code is valid since i=2 introduce i as a global variable which will merely be masked during the for statement:

function foo() {
    i = 2;
    for [i in 0...10]
        print(i); // the output will be 0123456789
    print(i); // the output will be 2
}

List of block structures that introduces a new scope for local variables:

  • block statements { }

  • if, else statements

  • iterated assignment statements

  • iterated function call

  • try/catch statements

  • with statements

  • for loops

  • while, do-while loops

Memory management

Internally the modeler uses a reference counting mechanism to manage memory. Each value is associated to a reference counter. This counter is increased or decreased according to the operations performed on the value. When the reference counter reaches 0, the associated value is destroyed.

The reference counter is increased when:

  • The value is associated to a local variable or a global variable

  • The value is added to a map or associated to a field of an object

The reference counter is decreased when:

  • The previous assigned value is replaced by a new one

  • The value is removed from a map or another native structure

  • A local variable that contains the value is destroyed

This memory management is pretty simple and has the main advantage to be completely predictable. Unfortunately, this reference counting mechanism cannot handle reference cycles, i.e a value that refers directly or indirectly to itself. So if you have to deal with very big models, try to avoid cycles.

Note

The other advantage of the reference counting is that objects are reclaimed as soon as they become unreachable. This particular behavior can be used to close automatically native ressources like files as soon as they can no longer be referenced. However, it’s better not to rely on this behavior, and instead to use the “with” statement to properly free resources that have become useless.