ARC + Copy-on-Write (CoW)
One of Wysna’s defining engineering principles is Pure Value Semantics powered by Automatic Reference Counting (ARC) combined with Copy-on-Write (CoW).
The Problem with Traditional Runtimes
Section titled “The Problem with Traditional Runtimes”Traditional programming languages force a difficult trade-off:
- Tracing Garbage Collectors (Go, Java, C#): Introduce periodic background scans, unpredictable pauses, and high memory footprints, making them less suitable for hard real-time systems, embedded devices, or tight WebAssembly sandbox limits.
- Manual Allocation (C, C++): Fast and compact, but leads to use-after-free, double-free, and memory leak vulnerabilities.
- Strict Lifetime / Borrow Checkers (Rust): Eliminate GC without memory unsafety, but require developers to annotate lifetimes, navigate complex borrow checkers, and restructure code around single-owner rules.
How Wysna Solves It: ARC + CoW
Section titled “How Wysna Solves It: ARC + CoW”In Wysna, every complex data structure (str, list, dict, and struct) acts logically as an independent value, while physically sharing underlying memory buffers until a mutation occurs.
Step 1: Assignment (let b = a)┌──────────────┐│ Variable a ├──┐└──────────────┘ │ ┌──────────────────────┐ ├──────►│ Shared Data Buffer │ (refcount = 2)┌──────────────┐ │ │ [ 10, 20, 30 ] ││ Variable b ├──┘ └──────────────────────┘└──────────────┘
Step 2: Mutation on b (b.append(40)) -> CoW triggers!┌──────────────┐ ┌──────────────────────┐│ Variable a ├─────────►│ Original Buffer │ (refcount = 1)└──────────────┘ │ [ 10, 20, 30 ] │ └──────────────────────┘┌──────────────┐ ┌──────────────────────┐│ Variable b ├─────────►│ Cloned Buffer │ (refcount = 1)└──────────────┘ │ [ 10, 20, 30, 40 ] │ └──────────────────────┘1. Fast, Cheap Copies
Section titled “1. Fast, Cheap Copies”When you pass a list to a function or assign it to another variable:
let original = [10, 20, 30]let copy = original # Increments refcount. No buffer allocation occurs!The underlying buffer is shared, and its reference count increments atomically or locally.
2. Transparent Mutation via Copy-on-Write
Section titled “2. Transparent Mutation via Copy-on-Write”When a variable attempts to mutate a shared buffer:
let mut updated = copyupdated[0] = 99 # Checks refcount: > 1, so it allocates a fresh buffer!- If
refcount == 1: The mutation occurs in place, with zero allocation overhead. - If
refcount > 1: The runtime clones the buffer, decrements the original’s reference count, and applies the mutation exclusively to the new copy.
Example: Value Semantics in Action
Section titled “Example: Value Semantics in Action”struct DatabaseConfig { host: str port: int}
fn main() -> unit { let prod_cfg = DatabaseConfig { host: "prod.internal", port: 5432, }
let mut staging_cfg = prod_cfg staging_cfg.host = "staging.internal"
# Both configurations are completely isolated: print("Prod Host: ", prod_cfg.host) # prod.internal print("Staging Host:", staging_cfg.host) # staging.internal}Summary of Benefits
Section titled “Summary of Benefits”- Zero Garbage Collection Stalls: No stop-the-world pauses.
- Immediate Destruction: Memory is reclaimed the microsecond its owner variable exits scope.
- No Dangling Pointers: The compiler guarantees that pointers are managed exclusively by the runtime runtime primitives.