Chapters

The Four Ownership Kinds

Learn which values can be used, and how many times.

7.1 Understand moves first

Ownership tracks which name has the right to use a value. When a nonduplicable value is passed to a new variable, the old name can no longer use it. This is a move.

Tauto organizes usage rules into four kinds.

KindDuplicateDiscardTypical meaning
copyYesYesBitwise copies of small values
sharedYesYesShared data read from several places
affineNoYesA resource used at most once
linearNoNoA resource used exactly once

The relation is copy ⊑ shared ⊑ affine ⊑ linear. copy and shared permit the same number of uses but have different runtime duplication costs: shared uses reference counting.

i64 and Bool are copy, Text is shared, and Vec(A) is affine. Declare a kind for your own type with forms such as affine struct File {} or linear enum Handshake { ... }. A declaration that permits more uses than the structure allows is a type error.

7.2 Vec is affine

ch07-vec.taut
import std::prelude::Affine

var v := Vec::new()
Vec::push(&mut v, 3)
Vec::push(&mut v, 4)

let size := Vec::len(&v)
perform show("size", size)

// Borrow the vector to append elements and inspect its size.
Execution result
size = 2
size = 2

Vec(A) is a mutable sequence of elements. Vec::push(&mut v, ...) temporarily borrows v to update its contents rather than taking ownership (borrowing is the next chapter's subject).

Passing a Vec directly to a function transfers ownership.

ch07-move.taut
import std::prelude::Affine

fn consume(v: Vec(i64)): u64 {
  Vec::len(&v)
}

var v := Vec::new()
Vec::push(&mut v, 1)
let n := consume(v)
Vec::push(&mut v, 2)

// This deliberately uses a vector after transferring ownership.
✗ Error
・ consume

error 10:11: v is borrowed after move

After consume(v), the caller no longer owns v. Attempting to use it is rejected before execution.

ch07-move.taut:10:10: use error: v is borrowed after move

This is the basic idea that prevents a resource from being used twice. Remove the final line and the program is accepted.

7.3 Sharing does not guarantee every safety property

shared values are easy to use because they can be duplicated freely, but duplication carries costs such as reference counting. Being shareable is different from being free of reference cycles and memory leaks. Ownership checking alone does not statically rule out every leak.

Exercise 7.1: Should a function that only reads a Vec take ownership or a borrow? Explain your choice.