Global variables

### 6.21 Global variables

GNU Prolog provides a simple and powerful way to assign and read global variables. There are 3 kinds of objects which can be associated to a global variable:

- a copy of a term (the assignment can be made backtrackable or not).
- a link to a term.
- an array of objects.

The initial value of a global variable is the integer 0. A global variable is referenced by a name (i.e. name = an atom) possibly indexed if it is an array (i.e. name = a compound term). In the following, `GVarName` represents such a reference to a global variable and its syntax is as follows:

  `GVarName` | ::= | `atom`
  |  | `atom``(``Index``,`...`,``Index``)`
  `Index` | ::= | `integer`
  |  | `GVarName`

When a `GVarName` is used as an index, the value of this variable must be an integer. Indexes range from 0 to `Size`-1 if the array has `Size` elements. The space necessary for copies and arrays are dynamically allocated and recovered as soon as possible. For instance, when an atom is associated to a global variable whose current value is an array, the space for this array is recovered (unless the assignment is to be undone when backtracking occurs).
Arrays: the predicates `g_assign/2`, `g_assignb/2` and `g_link/2` (section 6.21.1) define an array when the assigned value is a compound term with principal functor `g_array`. Then an array is assigned to `GVarName`. There are 3 forms for the term `g_array`:

- `g_array(Size)`: if `Size` is an integer > 0 then defines an array of `Size` elements which are all initialized with the integer `0`.
- `g_array(Size, Initial)`: as above but the elements are initialized with the term `Initial` instead of 0. `Initial` can contain other array definitions allowing thus for multi-dimensional arrays. Some examples are presented later (section 6.21.4).
- `g_array(List)`: as above if `List` is a list of length `Size` except that the elements of the array are initialized according to the elements of `List` (which can contain other array definitions).

The compound term with principal functor `g_array_extend` can be used instead of `g_array` to modify the structure of a (possibly) existing array. In that case, the existing elements of the array are not initialized.
When an array is read, a term of the form `g_array([Elem0,..., ElemSize-1])` is returned.

#### 6.21.1 `g_assign/2`, `g_assignb/2`, `g_link/2`

Templates

  `g_assign(+callable_term, ?term)
  g_assignb(+callable_term, ?term)
  g_link(+callable_term, ?term)`

Description
`g_assign(GVarName, Value)` assigns a copy of the term `Value` to `GVarName`. This assignment is not undone when backtracking occurs.
`g_assignb/2` is similar to `g_assign/2` but the assignment is undone at backtracking.
`g_link(GVarName, Value)` makes a link between `GVarName` to the term `Value`. This allows the user to give a name to any Prolog term (in particular non-ground terms). Such an assignment is always undone when backtracking occurs (since the term may no longer exist). If `Value` is an atom or an integer, `g_link/2` and `g_assignb/2` have the same behavior. Since `g_link/2` only handles links to existing terms it does not require extra memory space and is not expensive in terms of execution time.
Errors

`GVarName` is a variable |  | `instantiation_error`
`GVarName` is neither a variable nor a callable term |  | `type_error(callable, GVarName)`
`GVarName` is a compound term and a sub-argument `E` is not a valid index (section 6.21) |  | `domain_error(g_array_index, E)`

Portability
GNU Prolog predicates.

#### 6.21.2 `g_read/2`

Templates

  `g_read(+callable_term, ?term)`

Description
`g_read(GVarName, Value)` unifies `Value` with the term assigned to `GVarName`.
Errors

`GVarName` is a variable |  | `instantiation_error`
`GVarName` is neither a variable nor a callable term |  | `type_error(callable, GVarName)`
`GVarName` is a compound term and a sub-argument `E` is not a valid index (section 6.21) |  | `domain_error(g_array_index, E)`

Portability
GNU Prolog predicate.

#### 6.21.3 `g_array_size/2`

Templates

  `g_array_size(+callable_term, ?integer)`

Description
`g_array_size(GVarName, Value)` unifies `Size` with the dimension (an integer > 0) of the array assigned to `GVarName`. Fails if `GVarName` is not an array.
Errors

`GVarName` is a variable |  | `instantiation_error`
`GVarName` is neither a variable nor a callable term |  | `type_error(callable, GVarName)`
`GVarName` is a compound term and a sub-argument `E` is not a valid index (section 6.21) |  | `domain_error(g_array_index, E)`
`Size` is neither a variable nor an integer |  | `type_error(integer, Size)`

Portability
GNU Prolog predicate.

#### 6.21.4 Examples

A simple counter: the following predicate defines a counter using a global variable:

      inc(Var, Value) :-
              g_read(Var, Value),
              X is Value+1,
              g_assign(Var, X).

The query: `inc(c, X)` will succeed unifying `X` with `0`, another call to `inc(a, Y)` will then unify `Y` with `1`, and so on.
Difference between `g_assign/2` and `g_assignb/2`: `g_assign/2` does not undo its assignment when backtracking occurs whereas `g_assignb/2` undoes it.

  `test(Old) :-` | ```` | `testb(Old) :-`
  `g_assign(x,1),` | ```` | `g_assign(x,1),`
  `( g_read(x, Old),` | ```` | `( g_read(x, Old),`
  `` `g_assign``(x, 2)` | ```` | `` `g_assignb``(x, 2)`
  `; g_read(x, Old),` | ```` | `; g_read(x, Old),`
  `g_assign(x, 3)` | ```` | `g_assign(x, 3)`
  `).` | ```` | `).`

  ``

The query `test(Old)` will succeed unifying `Old` with `1` and on backtracking with `2` (i.e. the assignment of the value `2` has not been undone). The query `testb(Old)` will succeed unifying `Old` with `1` and on backtracking with `1` (i.e. the assignment of the value `2` has been undone).
Difference between `g_assign/2` and `g_link/2`: `g_assign/2` (and `g_assignb/2`) creates a copy of the term whereas `g_link/2` does not. `g_link/2` can be used to avoid passing big data structures (e.g. dictionaries,...) as arguments to predicates.

  `test(B) :-` | ```` | `test(B) :-`
  `` `g_assign``(b, f(X)),` | ```` | `` `g_link``(b, f(X)),`
  `X=12,` | ```` | `X=12,`
  `g_read(b, B).` | ```` | `g_read(b, B).`

  ``

The query `test(B)` will succeed unifying `B` with `f(_)` (`g_assign/2` assigns a copy of the value). The query `testl(B)` will succeed unifying `B` with `f(12)` (`g_link/2` assigns a pointer to the term).
Simple array definition: here are some queries to show how arrays can be handled:

      | ?- g_assign(w, g_array(3)), g_read(w, X).

      X = g_array([0,0,0])

      | ?- g_assign(w(0), 16), g_assign(w(1), 32), g_assign(w(2), 64), g_read(w, X).

      X = g_array([16,32,64])

this is equivalent to:

      | ?- g_assign(k, g_array([16,32,64])), g_read(k, X).

      X = g_array([16,32,64])

      | ?- g_assign(k, g_array(3,null)), g_read(k, X), g_array_size(k, S).

      S = 3
      X = g_array([null,null,null])

2-D array definition:

      | ?- g_assign(w, g_array(2, g_array(3))), g_read(w, X).

      X = g_array([g_array([0,0,0]),g_array([0,0,0])])

      | ?- (   for(I,0,1), for(J,0,2), K is I*3+J, g_assign(w(I,J), K),
               fail
           ;   g_read(w, X)
           ).

      X = g_array([g_array([0,1,2]),g_array([3,4,5])])

      | ?- g_read(w(1),X).

      X = g_array([3,4,5])

Hybrid array:

      | ?- g_assign(w,g_array([1,2,g_array([a,b,c]), g_array(2,z),5])), g_read(w, X).

      X = g_array([1,2,g_array([a,b,c]), g_array([z,z]),5])

      | ?- g_read(w(1), X), g_read(w(2,1), Y), g_read(w(3,1), Z).

      X = 2
      Y = b
      Z = z

      | ?- g_read(w(1,2),X).

      {exception: error(domain_error(g_array_index,w(1,2)),g_read/2)}

Array extension:

      | ?- g_assign(a, g_array([10,20,30])), g_read(a, X).

      X = g_array([10,20,30])

      | ?- g_assign(a, g_array_extend(5,null)), g_read(a, X).

      X = g_array([10,20,30,null,null])

      | ?- g_assign(a, g_array([10,20,30])), g_read(a, X).

      X = g_array([10,20,30])

      | ?- g_assign(a, g_array_extend([1,2,3,4,5,6])), g_read(a, X).

      X = g_array([10,20,30,4,5,6])

Verbatim copying and distribution of this entire article is permitted in any medium, provided this notice is preserved.
More about the copyright