Changeable Sharing: Mut<T>

Mut lets a function modify data in place — updating the original array or object directly instead of returning a copy. It’s like Shared, but with write access, and Cuttlefish checks that only one part of your program has that write access at a time.

Key benefits

  1. Change in place. A function can update an array or object without making and returning a duplicate — important on boards with little memory.
  2. Clear intent. Marking a parameter Mut is a readable signal that the function will change the data you pass it.

Safety Enforcements

Error: ownership-borrow-mismatch

You cannot pass an immutable Shared to a function that expects a Mut. This prevents a “read-only” contract from being violated.

function clear(buf: Mut<Uint8Array>) {
  buf.fill(0);
}

const data: Shared<Uint8Array> = ...; // Immutable
clear(data); // ERROR: Cannot pass 'data' (immutable Shared) to 'clear' (Mut).

Warning: Mut Exclusivity

To prevent race conditions and data corruption, Cuttlefish’s static analyzer warns you if you attempt to create multiple Mut borrows of the same source simultaneously.


Lifetime and Scope

Just like Shared, a Mut is a “borrow” and must not outlive its source.

Error: ownership-dangling-borrow

Occurs if a Mut in an outer scope persists after the Owned source in an inner scope has been destroyed.

let saved: Mut<number>;
{
  let local: Owned<number> = 42;
  saved = local; // ERROR: 'saved' borrows 'local' which goes out of scope.
}

API Summary

FeatureDescription
Read/Write AccessAllows both reading and modifying the underlying data.
C++ EmissionEmits T& for complex types, ensuring in-place modification.
Zero-CopyShares the existing memory address without duplication.

When to use Mut vs Owned

  • Use Mut when you want to modify a buffer that belongs to someone else (the caller).
  • Use Owned when you want to take full responsibility for the data (e.g., storing it in a global class instance or a task queue).