> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sifr.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Ownership and Mutability in Sifr

> Learn Sifr's borrow-by-default model, explicit mutability with mut, ownership transfer with own, and owned mutable parameters with own mut.

Sifr gives you Rust's memory-safety guarantees without making every call site look like Rust. Function parameters borrow by default, parameter mutation is explicit, and ownership transfer is opt-in. Most code starts with a plain parameter and reaches for `mut`, `own`, or `own mut` only when the function's contract needs it.

## Parameter Conventions

| Parameter style            | Meaning                 | Caller keeps value? | Callee can mutate?                     |
| -------------------------- | ----------------------- | ------------------- | -------------------------------------- |
| `items: list[int]`         | Immutable borrow        | Yes                 | No                                     |
| `mut items: list[int]`     | Mutable borrow          | Yes                 | Yes, during the call                   |
| `own items: list[int]`     | Owned immutable binding | No                  | No, unless copied into a mutable local |
| `own mut items: list[int]` | Owned mutable binding   | No                  | Yes                                    |

This table is the core model. A bare heap parameter is borrowed immutably. `mut` lets the function update the caller's value during the call. `own` moves the value into the function. `own mut` moves it and lets the function change it.

The same conventions apply to class methods. In particular, a bare move-only
method parameter is borrowed and cannot be returned or stored as an owned
value; spell it `own` when the method intentionally consumes it.

## Borrow By Default

When you pass a heap value to a function, Sifr borrows it by default. The function can read the value, and the caller keeps ownership.

```python theme={null}
def get_length(items: list[int]) -> int:
    return len(items)

def main():
    values: list[int] = [10, 20, 30]
    length: int = get_length(values)
    print(length)
    print(values)  # still usable
```

Bare parameters are immutable. The callee cannot reassign the parameter name or mutate the object behind it.

```python theme={null}
def count_items(items: list[int]) -> int:
    # items.append(0) would be rejected
    return len(items)
```

## `mut` For Mutable Borrows

Use `mut` when the function should update the caller's value in place.

```python theme={null}
def append_all(mut target: list[bool], values: list[bool]) -> None:
    for value in values:
        target.append(value)

def main():
    checks: list[bool] = []
    append_all(checks, [True, False])
    print(checks)  # [True, False]
```

`mut` is required both for rebinding a parameter name and for mutating through a heap parameter. Rebinding a mutable borrowed parameter to another value still does not make the borrowed value owned.

<Warning>
  A mutable borrow cannot escape. `mut items: list[int]` can update the caller's list during the call, but it cannot return `items` or store it as an owned value. Use `own`, `own mut`, or `items.clone()` depending on whether the function should consume, mutate, or copy the value.
</Warning>

## `own` And `own mut`

Use `own` when a function consumes a value. After the call, the caller cannot use the moved value.

```python theme={null}
def consume_and_count(own items: list[int]) -> int:
    return len(items)

def main():
    values: list[int] = [1, 2, 3]
    count: int = consume_and_count(values)
    print(count)
    # values is moved here
```

Use `own mut` when the function consumes a value and needs to mutate it.

```python theme={null}
def append_zero(own mut values: list[int]) -> list[int]:
    values.append(0)
    return values

def main():
    updated: list[int] = append_zero([2, 3, 4])
    print(updated)  # [2, 3, 4, 0]
```

<Tip>
  `own mut` is the canonical spelling. The formatter rewrites `mut own` to `own mut`.
</Tip>

## Scalars And Immutable Values

Scalar values such as `int`, `float`, and `bool` behave like ordinary values at the source level. A `mut n: int` parameter permits local rebinding inside the function, but it does not create an observable heap borrow or ownership transfer.

```python theme={null}
def increment(mut n: int) -> int:
    n = n + 1
    return n
```

Some types are immutable by design. For example, `mut` does not make `bytes` subscript assignment legal.

## Across `await`

Mutable borrows cannot remain live across an `await` point. End the mutation before awaiting, move owned data into a task, or wrap shared state in an explicit synchronization primitive.

```python theme={null}
def append_before_await(mut items: list[int]) -> None:
    items.append(1)

async def main() -> None:
    values: list[int] = []
    append_before_await(values)
    await task.sleep(0.0)
```

For the task-boundary model, see [Concurrency](/language/concurrency).

## Rules At A Glance

| Need                                      | Use                                        |
| ----------------------------------------- | ------------------------------------------ |
| Read a value without taking it            | `items: list[int]`                         |
| Update the caller's value during the call | `mut items: list[int]`                     |
| Consume a value                           | `own items: list[int]`                     |
| Consume and mutate a value                | `own mut items: list[int]`                 |
| Keep a borrowed value after the call      | `.clone()` or change the boundary to `own` |

<CardGroup cols={2}>
  <Card title="Coming from Python?" href="/guides/python-developers">
    Follow a path through mutation, typed errors, imports, and packages.
  </Card>

  <Card title="Coming from Rust?" href="/guides/rust-developers">
    Map `mut`, `own`, and borrow-by-default rules back to Rust concepts.
  </Card>
</CardGroup>
