| name | ownership-type-system |
| description | Implements ownership and borrowing type system (Rust-style). Use when: (1) Verifying memory safety, (2) Data race prevention, (3) Lifetime analysis. |
| version | 1.0.0 |
| tags | ["type-systems","ownership","borrowing","rust"] |
| difficulty | advanced |
| languages | ["python","rust"] |
| dependencies | ["linear-type-implementer"] |
Ownership Type System
Implements ownership types with borrowing and lifetimes.
When to Use
- Verifying memory safety
- Preventing data races
- Lifetime analysis
- Resource management
What This Skill Does
- Implements ownership - Each value has single owner
- Handles borrowing - Mutable and immutable references
- Verifies lifetimes - Lexical lifetimes
- Checks borrowing rules - Aliasing XOR mutability
Core Rules
Ownership Rules:
- Each value has exactly one owner
- When owner goes out of scope, value is dropped
- Ownership can be transferred (move)
- Ownership can be borrowed (reference)
Borrowing Rules:
- Either OR many immutable references
- OR exactly one mutable reference
- References must not outlive borrowed data
Implementation
from dataclasses import dataclass, field
from typing import Dict, List, Set, Optional
from enum import Enum
class Ownership(Enum):
OWNED = "owned"
BORROWED_MUT = "borrowed_mut"
BORROWED_IMMUT = "borrowed_immut"
@dataclass
class Type:
"""Ownership type"""
base: str
ownership: Ownership
lifetime: Optional['Lifetime'] = None
@dataclass
class Lifetime:
"""Lifetime region"""
name: str
upper_bound: Optional['Lifetime'] = None
@dataclass
class Variable:
"""Variable with ownership info"""
name: str
typ: Type
is_mutable: bool
@dataclass
class Borrow:
"""Borrow expression"""
borrower: str
lender: str
is_mutable: bool
lifetime: Lifetime
class OwnershipChecker:
"""Check ownership and borrowing"""
def __init__(self):
self.variables: Dict[str, Variable] = {}
self.borrows: List[Borrow] = []
self.errors: List[str] = []
def check_program(self, program: 'Program') -> bool:
"""Check ownership rules"""
self.variables = {}
self.borrows = []
self.errors = []
for stmt in program.statements:
self.check_statement(stmt)
return len(self.errors) == 0
def check_statement(self, stmt: 'Stmt'):
"""Check single statement"""
match stmt:
case Let(x, typ, value):
self.variables[x] = Variable(x, typ, False)
case Move(x, y):
if y in self.variables:
active = [b for b in self.borrows if b.lender == y]
if active:
self.errors.append(
f"Cannot move '{y}': has {len(active)} active borrows"
)
self.variables[x] = self.variables.pop(y)
case BorrowRef(x, y, mutable):
if y not in self.variables:
self.errors.append(f"Cannot borrow undeclared variable: {y}")
return
lender = self.variables[y]
existing_borrows = [b for b in self.borrows if b.lender == y]
if mutable:
if existing_borrows:
self.errors.append(
f"Cannot mutably borrow '{y}': already borrowed"
)
if lender.is_mutable:
self.errors.append(
f"Cannot mutably borrow already mutable variable: {y}"
)
else:
mutable_borrows = [b for b in existing_borrows if b.is_mutable]
if mutable_borrows:
self.errors.append(
f"Cannot immutably borrow '{y}': already mutably borrowed"
)
borrow = Borrow(x, y, mutable, Lifetime("scope"))
self.borrows.append(borrow)
self.variables[x] = Variable(x, Type(lender.typ.base,
Ownership.BORROWED_MUT if mutable else Ownership.BORROWED_IMMUT), mutable)
case Assign(x, y):
if x in self.variables:
x_var = self.variables[x]
if x_var.typ.ownership != Ownership.OWNED:
self.errors.append(f"Cannot assign to borrowed variable: {x}")
case Drop(x):
if x in self.variables:
active = [b for b in self.borrows if b.lender == x]
if active:
self.errors.append(
f"Cannot drop '{x}': has {len(active)} active borrows"
)
del self.variables[x]
def check_lifetime(self, borrow: Borrow, lender_var: Variable) -> bool:
"""Check borrow lifetime"""
if borrow.lifetime and lender_var.typ.lifetime:
return self.lifetime_sub(borrow.lifetime, lender_var.typ.lifetime)
return True
def lifetime_sub(self, sub: Lifetime, sup: Lifetime) -> bool:
"""Check sub ≤ sup"""
return True
def examples():
"""
Valid:
let x = Vec::new();
let y = &x; // immutable borrow
let z = &x; // multiple immutable OK
Invalid:
let x = Vec::new();
let y = &mut x; // mutable borrow
let z = &x; // immutable after mutable
Move semantics:
let x = Vec::new();
let y = x; // x moved to y
// x no longer valid
"""
pass
Key Concepts
| Concept | Description |
|---|
| Ownership | Single owner per value |
| Borrow | Temporary reference |
| Move | Transfer ownership |
| Lifetime | Region of validity |
| Borrow checking | Aliasing XOR mutability |
Rust Borrowing Rules
Rules:
1. &T: Multiple immutable references OK
2. &mut T: Only one mutable reference
3. No references to references (directly)
4. &mut only from owned or &mut
5. Lifetime: borrow must not outlive lender
Tips
- Track active borrows
- Handle drops correctly
- Check lifetime relationships
- Consider interior mutability
Related Skills
linear-type-implementer - Linear types
garbage-collector-implementer - GC
type-checker-generator - Type checking
Canonical References
| Reference | Why It Matters |
|---|
| Clarke, Potter, Noble, "Ownership Types for Flexible Alias Protection" (OOPSLA 1998) | Original ownership types paper |
| Noble, Vitek, Potter, "Flexible Alias Protection" (ECOOP 1998) | Conceptual foundation for ownership types |
| Boyland, "Alias Burying: Unique Variables Without Destructive Reads" (2001) | Uniqueness without destructive reads |
| Tofte & Talpin, "Region-Based Memory Management" (Information and Computation, 1997) | Region-based memory for ML |
| Clarke, Drossopoulou, "Ownership, Encapsulation and the Disjointness of Type and Effect" (OOPSLA 2002) | Ownership and effects |
Tradeoffs and Limitations
Ownership Approach Tradeoffs
| Approach | Pros | Cons |
|---|
| Rust-style | Safe, no GC | Complexity |
| Regions | Fast | Complex regions |
| Unique pointers | Simple | Limited |
| Capabilities | Flexible | Hard to use |
When NOT to Use Ownership Types
- For simple programs: GC is simpler
- For rapid prototyping: Ownership adds overhead
- For shared state: Use Arc/Rc instead
Complexity Considerations
- Borrow checking: O(n) per borrow
- Lifetimes: Can require annotations
- Error messages: Complex to explain
Limitations
- Learning curve: Complex rules to learn
- Error messages: Can be cryptic
- Interior mutability: Requires special handling (Cell, RefCell)
- Lifetimes: Must be explicit or inferred
- Async: Lifetimes with async complex
- Interoperability: FFI complexity
- Shared ownership: Not zero-cost
Research Tools & Artifacts
Ownership systems:
| System | What to Learn |
|---|
| Rust | Ownership/borrowing |
| PyOxygen | Ownership in Python |
Research Frontiers
1. Linear Types in Haskell
Implementation Pitfalls
| Pitfall | Real Consequence | Solution |
|---|
| Borrow errors | Rejected programs | Learn patterns |