Values are usually copied as they flow from function-to-function or variable-to-variable. Changes made to a copy won't alter the original value.

imm a = 3
mut b = a  // b holds a copy of a's value
b += 1     // b's value is changed to 4
a          // is still 3

Values of certain types, however, may not be copied. Such values may only be moved.

This "no-copy" restriction is typically oriented around non-aliasable references, making possible some useful capabilities:

Despite their usefulness, 'move' values do introduce some complications, as they don't always behave like 'copy' values. In particular, moving a value deactivates its source variable and changes its scope, thereby delaying or accelerating its demise. This page explains these important behaviors.

Copy vs. Move Types

A value's type dictates whether its values are treated as 'copy' or 'move'. By default, most types are 'copy'. The 'move' types include:

Note: Any user-defined type that implements the .clone method makes that type 'copy', even if it would otherwise be 'move'. This is because the .clone method is considered a copy constructor which implements a safe way to copy this type's values.

Variable Deactivation

Let's see what happens when we do a 'move':

imm nbr = &own 5
imm newvar = nbr   // the ref has been moved to newvar
imm b = *nbr       // **ERROR** nbr no longer has a usable value

We have a simple reason for deactivating the variable 'nbr' after the move. If we had not done so, we would effectively end up with two copies of a value that is supposed to be non-copyable. By deactivating 'nbr', we ensure there is only ever one usable copy in existence.

The same principle holds true when passing a 'move' value to another function.

imm nbr = &own 5
afunction(nbr)    // the ref is moved to the called function
anotherfunc(nbr)  // **ERROR** nbr is deactivated

Borrowing references can deactivate variable

Source variables are also deactivated whenever a borrowed reference is created to (or out of) a 'move' value. This deactivation is only temporary; the original variable's use is restored after the borrowed reference expires:

imm nbr = &own 5
do
  imm nbrref &u32 = nbr  // Create a borrowed reference
  // nbr is no longer usable in this Scope
afunction(nbr) // nbr is usable again now that nbrref is gone

Forbidden moves

Sometimes a move is not allowed, even on a 'move' value. This happens whenever it is not possible to cleanly deactivate the source of the value. For this reason, you may not move a 'move' value out of any kind of array or by derefencing it out of a borrowed reference.

It is possible to move a 'move' value out of a particular struct's field, but doing so deactivates use of the entire original struct.

Swapping 'move' values

swap may be used to safely swap two 'move' values:

mut a = &own 5
mut b = &own 6
swap a,b
// a now points to 6 and b points to 5

swap offers a helpful way to get around forbidden moves. One can temporarily extract a 'move' value out of a borrowed reference or array by swapping it with some arbitrary type-compatible value. After making use of the extracted value, simply swap it back in.

fn func(arrref &[] &own u32, index u32)
  mut work = &own 0         // Set up the work area with a dummy value
  swap work, arrref[index]  // Extract the desired 'move' value
  imm retval = *work        // Make use of the extracted 'move' value
  swap work, arrref[index]  // Restore the original value back into the array
  retval

The reason why this works is that the original source always has a usable 'move' value, (even if it is only a dummy value). That ensures that the original source is always completely safe to use.

Scope escapes and Destruction

In addition to variable deactivation, moving a value effectively changes its lexical scope to that of its new variable that owns it. Why this matters is that 'move' values are effectively dropped and/or destroyed at the end of the last scope they are moved into. So, by allowing a move value to hop from scope to scope, you effectively lengthen or shorten its effective lifetime.

It is legal for 'move' values to move (or not) based on conditional decisions made at run-time. These are called conditional moves.

Explicit destruction

There is an easy way to ensure the immediate destruction of a 'move' value. Just assign it to the anonymous variable "_":

imm ref = &own 5
_ = ref
callfn(ref)   // **ERROR**. ref is deactivated

Doing this on a 'copy' value does nothing.

_