# Chapter 12: Unique Ownership

A freestanding image has no reference counts, so "who owns this object, and when is it done?" must be answered at compile time. `unique` is how Loup answers it: a `unique` value has exactly one owner at a time, ownership moves on assignment, and the compiler rejects every use of a binding whose value has moved on (Language Reference §3-2.4.7). Moves cost nothing at run time — there is no count to adjust.

This chapter covers `unique class` and `unique` bindings, moves, `takes`, moving out of borrows, loops, closures, structs that hold `unique` values, and `del`.

## `unique class` and `unique` bindings

A `unique class` is a class whose instances always have a single owner. A plain class can also be held uniquely by declaring the binding `unique let` or `unique var`:

```loup
@mode(freestanding)

unique class PageFrame {
    pub var number: uint64;
    new(number: uint64) { this.number = number; }

    reads func address(): uint64 {
        return this.number * 4096u64
    }
}

class Mailbox {
    pub var pending: uint32 = 0;
}

func setUp(): uint64 {
    let frame = PageFrame(0x42u64)       # unique because the class is
    unique let box = Mailbox()           # unique because the binding is
    unique var scratch = Mailbox()
    scratch = Mailbox()                  # a unique var may be rebound
    return frame.address() + (box.pending as uint64) + (scratch.pending as uint64)
}
```

*Listing 12-1: A `unique class` and `unique` bindings*

`unique` applies to class values only. Structs, enums and primitives are values already — each copy is independent — so `unique let p = Point(x = 1)` is `E_UNIQUE_NOT_CLASS: 'unique' can only be applied to class types, not 'Point'`.

## Moves

Assigning a `unique` value to another binding moves it; the old binding is dead:

```loup,does_not_compile
@mode(freestanding)

unique class PageFrame {
    pub var number: uint64;
    new(number: uint64) { this.number = number; }
}

func mapKernelPage(): uint64 {
    let frame = PageFrame(0x42u64)
    let mapped = frame                  # meant: "look at the same frame"
    return frame.number * 4096u64
}
```

```text
error[E_USE_AFTER_MOVE]: E_USE_AFTER_MOVE: binding 'frame' was moved and cannot be used again — `unique class` instances and move-only structs have single ownership
  --> src/main.lpfree:11:12
   |
11 |     return frame.number * 4096u64
   |            ^^^^^
   |
```

In a hosted mode `let mapped = frame` would make a second reference to the same object. A `unique` object cannot have two, so the assignment transfers ownership to `mapped`. If you only need to look at the frame, borrow it instead — pass it to a `reads` parameter, which leaves the caller's binding intact:

```loup
#~ @mode(freestanding)
#~
#~ unique class PageFrame {
#~     pub var number: uint64;
#~     new(number: uint64) { this.number = number; }
#~ }
#~
func frameAddress(frame: PageFrame): uint64 {   # an implicit `reads` borrow
    return frame.number * 4096u64
}

func clear(edits frame: PageFrame): void {      # an exclusive borrow
    frame.number = 0u64
}

func mapKernelPage(): uint64 {
    let frame = PageFrame(0x42u64)
    let address = frameAddress(frame)           # borrowed, still ours
    clear(edits: frame)                         # borrowed exclusively, still ours
    return address + frame.number
}
```

*Listing 12-2: Borrowing a `unique` value leaves the owner in place*

Because a `unique` value has no aliases, an `edits` borrow of it needs no run-time or compile-time alias search: exclusivity is already proven.

## `takes` — moving into a function

A `takes` parameter receives ownership; the call site writes `takes:` and the caller's binding is consumed (chapter 10). Returning a `unique` value moves it out to the caller. Together they express hand-offs precisely:

```loup
#~ @mode(freestanding)
#~
#~ unique class PageFrame {
#~     pub var number: uint64;
#~     new(number: uint64) { this.number = number; }
#~ }
#~
var nextFree: uint64 = 0x100
var freed: uint64 = 0

func allocFrame(): PageFrame {
    let f = PageFrame(nextFree)
    nextFree = nextFree + 1u64
    return f                                   # ownership moves to the caller
}

func freeFrame(takes f: PageFrame): void {
    freed = freed + 1u64                       # the allocator owns it now
}

func cycle(): uint64 {
    let f = allocFrame()
    let number = f.number
    freeFrame(takes: f)
    return number
}
```

*Listing 12-3: Ownership flowing out of an allocator and back*

### Moves inside loops

A move inside a loop body happens again on the next iteration, so the checker reports the second iteration's use (ruling LOOPMV-1):

```loup,does_not_compile
@mode(freestanding)

unique class PageFrame {
    pub var number: uint64;
    new(number: uint64) { this.number = number; }
}

var freeFrames: uint64 = 0

func freeFrame(takes f: PageFrame): void {
    freeFrames = freeFrames + 1u64
}

func freeRange(count: int): void {
    let frame = PageFrame(0x100u64)
    var i = 0
    while (i < count) {
        freeFrame(takes: frame)
        i = i + 1
    }
}
```

```text
error[E_USE_AFTER_TAKE]: E_USE_AFTER_TAKE: binding 'frame' was consumed by a `takes` parameter in a previous iteration of the loop and cannot be used again
  --> src/main.lpfree:18:26
   |
18 |         freeFrame(takes: frame)
   |                          ^^^^^
   |
```

Each iteration needs its own value. Create it inside the loop:

```loup
#~ @mode(freestanding)
#~
#~ unique class PageFrame {
#~     pub var number: uint64;
#~     new(number: uint64) { this.number = number; }
#~ }
#~
#~ var freeFrames: uint64 = 0
#~
#~ func freeFrame(takes f: PageFrame): void {
#~     freeFrames = freeFrames + 1u64
#~ }
#~
func freeRange(first: uint64, count: int): void {
    var i = 0
    while (i < count) {
        let frame = PageFrame(first + (i as uint64))
        freeFrame(takes: frame)
        i = i + 1
    }
}
```

*Listing 12-4: A fresh `unique` value per iteration*

## Only `takes` parameters own their value

A parameter without `takes` is a borrow. Returning it, storing it, or passing it on to a `takes` parameter would move a value the function does not own (ruling MOVEB-1):

```loup,does_not_compile
@mode(freestanding)

unique class PageFrame {
    pub var number: uint64;
    new(number: uint64) { this.number = number; }
}

# Returns the frame a lookup found.
func pick(frame: PageFrame): PageFrame {
    return frame
}
```

```text
error[E_MOVE_OUT_OF_BORROW]: E_MOVE_OUT_OF_BORROW: cannot move `frame` out of the borrowed parameter `frame` — only a `takes` parameter owns its value (§1-8.11); declare it `takes frame`
  --> src/main.lpfree:10:12
   |
10 |     return frame
   |            ^^^^^
   |
```

The fix is in the message: `func pick(takes frame: PageFrame): PageFrame`, called as `pick(takes: f)`. The same rule covers a receiver: a `reads` or `edits` method cannot move out of `this` or out of one of its fields.

## Closures capture by moving

A closure that captures a `unique` binding — or any binding whose value holds one — moves it into the closure, whether or not the closure escapes (ruling CAPMV-1):

```loup,does_not_compile
@mode(freestanding)

unique class PageFrame {
    pub var number: uint64;
    new(number: uint64) { this.number = number; }
}

func describe(): uint64 {
    let frame = PageFrame(0x42u64)
    let address = func(): uint64 {
        return frame.number * 4096u64
    }
    let a = address()
    return frame.number
}
```

```text
error[E_USE_AFTER_MOVE]: E_USE_AFTER_MOVE: binding 'frame' was moved and cannot be used again — `unique class` instances and move-only structs have single ownership
  --> src/main.lpfree:14:12
   |
14 |     return frame.number
   |            ^^^^^
   |
```

Capture what the closure needs, not the owner: copy the plain value out first.

```loup
#~ @mode(freestanding)
#~
#~ unique class PageFrame {
#~     pub var number: uint64;
#~     new(number: uint64) { this.number = number; }
#~ }
#~
func describe(): uint64 {
    let frame = PageFrame(0x42u64)
    let number = frame.number                 # a uint64 copy
    let address = func(): uint64 {
        return number * 4096u64
    }
    let a = address()
    return a + frame.number
}
```

*Listing 12-5: Capturing a copied field instead of the `unique` owner*

## Structs that hold `unique` values

A struct field may hold a `unique` value, declared `unique var`. Such a struct becomes **move-only**: copying it would duplicate the owner, so `let b = a` moves it (§1-10.3.2):

```loup
#~ @mode(freestanding)
#~
#~ unique class PageFrame {
#~     pub var number: uint64;
#~     new(number: uint64) { this.number = number; }
#~ }
#~
struct Mapping {
    var virt: uint64;
    unique var frame: PageFrame;
}

func mapOne(virt: uint64, number: uint64): Mapping {
    return Mapping(virt = virt, frame = PageFrame(number))
}

func physical(m: Mapping): uint64 {
    return m.frame.number * 4096u64
}

func demo(): uint64 {
    let m = mapOne(0xFFFF_8000u64, 7u64)
    let p = physical(m)                       # borrowed: m is still ours
    let moved = m                             # moved: m is now dead
    return p + moved.virt
}
```

*Listing 12-6: A move-only struct holding a `unique` field*

A struct field must use `unique var`, not `unique let` (`E_UNIQUE_FIELD_LET`), and a plain class may not have `unique` fields — only a `unique class` or a struct can hold one (`E_UNIQUE_CLASS_FIELD`).

Collections are a hosted feature (chapter 13 explains why freestanding code should not use growable `list`s), but the same rules apply to them: inserting a `unique` value consumes it, indexing borrows, and `pop`/`remove` move it out (ruling UNIQCOLL-1).

## `del` and the end of ownership

`del x` ends ownership early: it runs the class's `finalize()` method, and any later use of `x` is `E_USE_AFTER_DEL` (chapter 7 shows the diagnostic). In freestanding, keep two things in mind:

- The Language Reference also has `del` return the object's memory to the `@deallocator`. Like allocation itself, that half is planned, not implemented in 1.25 (chapter 7).
- Do not rely on implicit cleanup at the end of a scope. The Language Reference promises `finalize()` at `del` and at the end of a `with` block; `defer` blocks do not run in 1.25 (chapter 4). Call `del`, or a `takes` method such as `release()`, at the point where the resource really is done.

`consume`, which turns a `unique` value into an ARC reference in `host.native`, does not exist in freestanding: there is no ARC to hand the value to (`E_CONSUME_NOT_AVAILABLE`, chapter 7). When several parts of a kernel need the same object, keep one owner in a long-lived place — a module-level table — and lend borrows to the rest; or count references yourself with atomic intrinsics (chapter 23).

## Summary

- `unique class` and `unique let`/`unique var` bindings give a class value exactly one owner; `unique` on a non-class type is `E_UNIQUE_NOT_CLASS`.
- Assignment moves a `unique` value (`E_USE_AFTER_MOVE`); borrow with `reads`/`edits` parameters to keep ownership.
- `takes` moves into a function (`E_USE_AFTER_TAKE` afterwards, including on the next loop iteration); returning moves out.
- Only `takes` parameters may move their value onward (`E_MOVE_OUT_OF_BORROW`).
- Closures capture `unique` bindings by moving them; capture copied fields instead.
- A struct with a `unique var` field is move-only.
- `del` runs `finalize()` and ends the binding; release resources explicitly rather than at scope exit; `consume` is unavailable.

Next: memory primitives.
