Silu has no GC. The static world (typed path) uses **Rust-style
ownership rules; the dynamic world (pyobj) deliberately leaks**.
This document covers mechanisms, measured data, and the analysis of
why the static world doesn't need a borrow checker.
The typed path produces no garbage that needs tracking β every block of memory has a single owner from birth:
| Type | Representation | Lifetime Management |
|---|---|---|
int / float / bool | Stack values (i64/double/i1) | No heap allocation |
str (rawstr) | Exclusive heap buffer {len,cap,data,cp} | Full drop discipline: assignment copies and frees the old buffer; function exit drops all local slots (_emit_local_rawstr_drops); parameters are borrowed zero-copy (callee is read-only; s += x rebinds via concat β Python aliasing semantics hold precisely: h(d) returns "abx" while d remains "ab") |
list[int] etc. (rawlist) | Exclusive struct | Assignment is ownership transfer; no scope drop (static-program containers are typically built once) |
dict[int,int] etc. (rawdict) | Exclusive hash table | Same |
Measured (Apple Silicon):
reclaimed)
row = row + "*": 2.3ms (amortized O(1) in-place append)pyobj boxes ({i32 tag, i8* data}; create_int/str/list/dict/instance) are malloc'd and never freed β the runtime has no free path for user-level boxes.
Measured: 300K loop iterations, each creating a small list + dict: RSS 172MB (~570B/iteration, pure leak).
This is intentional:
performance plane
which has zero pyobj traffic
production memory efficiency
Rust needs a borrow checker because it allows mutation of shared data and requires preventing dangling references. Silu's static world avoids the problem structurally:
is unnecessary; a borrowed pointer is always valid
state means no dangling references
the callee cannot free what it doesn't own
The cost is that some Rust programs can't be written exactly (shared mutable containers with aliases). The benefit is that the compiler is simpler and the error messages are about types, not lifetimes.
| Aspect | Rust | Silu (static) | Silu (dynamic) |
|---|---|---|---|
| GC | No | No | No |
| Borrow checker | Yes | No | No |
| Memory leaks | None (safe code) | None (typed path) | By design |
| Shared mutable refs | Via Rc<RefCell<T>> | Not supported | Via pyobj boxing |
| Dangling refs | Prevented by borrow checker | Structurally impossible | Impossible (leak) |
| Learning curve | Steep (lifetimes) | Type annotations only | None |
| Performance overhead | Zero-cost abstractions | Zero (compile-time discipline) | Boxing cost |
The choice is deliberate:
targets systems-level work where these are unacceptable
a complex compiler implementation β Silu achieves memory safety through simpler structural rules (immutability + ownership transfer)
full CPython compatibility without GC complexity, and the typed path provides the escape hatch for performance-critical code