Certain special cases require a module to have one or more mutable (i.e. destructively updatable) variables, for example to hold the constraint store for a solver type.
A mutable variable is declared using the ‘mutable’ directive:
:- mutable(varname, vartype, initial_value, varinst, [attribute, …]).
This constructs a new mutable variable with access predicates that have the following signatures:
:- semipure pred get_varname(vartype::out(varinst)) is det. :- impure pred set_varname(vartype::in(varinst)) is det.
The initial value of varname is initial_value, which is set before the program’s ‘main/2’ predicate is executed.
The type vartype is not allowed to contain any type variables or have any type class constraints.
The inst varinst is not allowed to contain any inst variables.
It is also not allowed to be equivalent to,
or contain components that are equivalent to,
the builtin insts
The initial value of a mutable, initial_value, may be any Mercury expression with type vartype and inst varinst subject to the above restrictions. It may be impure or semipure.
The following attributes must be supported:
This attribute specifies whether the implementation should generate code to undo the effects of ‘set_varname/1’ on backtracking (‘trailed’) or not (‘untrailed’). The default, in case none is specified, is ‘trailed’.
This attribute causes the compiler to also construct access predicates that have the following signatures:
:- pred get_varname(vartype::out(varinst), io::di, io::uo) is det. :- pred set_varname(vartype::in(varinst), io::di, io::uo) is det.
This attribute causes the compiler to construct only a ‘get’ access predicate, but not a ‘set’ access predicate. Since varname will always have the initial value given to it, the ‘get’ access predicate is pure; its signature will be:
:- pred get_varname(vartype::out(varinst)) is det.
The ‘constant’ attribute cannot be specified together with the ‘attach_to_io_state’ attribute (since they disagree on this signature). It also cannot be specified together with an explicit ‘trailed’ attribute.
The Melbourne Mercury compiler also supports the following attributes:
Allow foreign code to access the mutable variable in some implementation dependent manner. Lang must be a valid target language for this Mercury implementation. Name must be a valid identifier in that language. It is an error to specify more than one foreign name attribute for each language.
For the C backends,
this attribute allows foreign code to access the mutable variable
as an external variable called Name.
For the low-level C backend, e.g. the asm_fast grades,
the type of this variable will be
For the high-level C backend, e.g. the hlc grades,
the type of this variable depends upon the Mercury type of the mutable.
For mutables of a Mercury primitive type,
the corresponding C type is given
by the mapping in C data passing conventions.
For mutables of any other type,
the corresponding C type will be
This attribute is not currently implemented for the non-C backends.
This attribute allows a mutable to take on different values in each thread. When a child thread is spawned, it inherits all the values of thread-local mutables of the parent thread. Changing the value of a thread-local mutable does not affect its value in any other threads.
The ‘thread_local’ attribute cannot be specified together with either of the ‘trailed’ or ‘constant’ attributes.
It is an error for a ‘mutable’ directive to appear in the interface section of a module. The usual visibility rules for sub-modules apply to the mutable variable access predicates.
For the purposes of determining when mutables are assigned their initial values, the expression initial_value behaves as though it were a predicate specified in an ‘initialise’ directive.
:- initialise foo/2. :- mutable(bar, int, 561, ground, [untrailed]). :- initialise baz/2.
In the above example, ‘foo/2’ is invoked first, then ‘bar’ is set with an initial value of 561 and the ‘baz/2’ is invoked.
The effect of a mutable initial value expression terminating with an uncaught exception is also the same as though it were a predicate specified in an ‘initialise’ directive.