Shadowing and Mutation
Edit on GitHubMutation
Value bindings in Grain are immutable by default, which means that they cannot be reassigned after being declared. While regular immutable bindings should be sufficient for most use cases, it can sometimes be helpful to mutate the data already associated with a name when writing imperative-style code. We can opt into mutable values by declaring a binding mut
when defined.
Using mut
Consider the following example:
1 | module Main |
A couple things to note:
- When defining our value binding, we added the
mut
keyword. - We can use the value of our mutable binding like any other binding.
- We can assign new values to the binding using
=
. - If we forget
mut
but try to assign to the binding, we’ll get a compilation error.
Working with Mutable Numbers
When using mutable values that are Numbers
, we can use some built-in operators to make working with them easier. Grain provides +=
, -=
, *=
, /=
, and %=
, which perform the math operation on the value and re-assign the result.
Unlike some other languages, these operators return void
to help alleviate ambiguity and make code easier to understand.
1 | module Main |
Shadowing
It is also possible to create a binding with the same name as an existing binding in the same scope; this process is called “shadowing” and can be an alternative to declaring mut
bindings if a binding value is changed in the same scope the original binding is declared in:
It is important to note that shadowing does not modify what the shadowed binding refers to, but rather makes a new association for a binding name within the scope:
1 | module Main |
Boxes
Boxes are special values in Grain that can be used for representing mutable data. The difference between boxes and let mut
is that let mut
allows you to update a binding to refer to a new value whereas a box is itself a value whose contents can be mutated. Generally, using let mut
is preferred to boxes, but boxes can be useful in more complex mutation scenarios.
- The
box
function allows you to create a box containing an initial value. - The
unbox
function allows you to access the current value inside a box. - The
:=
operator allows you to reassign the value inside a box.