Immutability
All types in Q# are value types. Q# does not have a concept of a reference or pointer. Instead, it allows you to reassign a new value to a previously declared variable via a set
statement. For example, there is no distinction in behavior between reassignments for variables of type Int
or variables of type Int[]
. Consider the following sequence of statements:
mutable arr1 = new Int[3];
let arr2 = arr1;
set arr1 w/= 0 <- 3;
The first statement instantiates a new array of integers [0,0,0]
and assigns it to arr1
.
The next statement assigns that value to a variable with name arr2
. The last statement creates a new array instance based on arr1
with the same values except for the value at index 0 which is set to 3. The newly created array is then assigned to the variable arr1
. The last line makes use of the abbreviated syntax for evaluate-and-reassign statements, and could equivalently have been written as set arr1 = arr1 w/ 0 <- 1;
.
After running the three statements, arr1
will contain the value [3,0,0]
while arr2
remains unchanged and contains the value [0,0,0]
.
Q# clearly thus distinguishes the mutability of a handle and the behavior of a type. Mutability within Q# is a concept that applies to a symbol rather than a type or value; it applies to the handle that allows you to access a value rather than to the value itself. It is not represented in the type system, implicitly or explicitly.
Of course, this is merely a description of the formally defined behavior; under the hood, the actual implementation uses a reference counting scheme to avoid copying memory as much as possible. The modification is specifically done in place as long as there is only one currently valid handle that accesses a certain value.