Bend 2 vs. Rust: Borrow-Checked Systems Programming vs. Affine Parallel Proof Kernels
An architectural and empirical comparison of Bend 2 and Rust
across Apple M4 Max CPU/GPU benchmarks, DevSecOps policy latency, Rayon
work-stealing vs. the BendRT Task Cube, and proptest
vs. LAWS.bend.
Executive Summary: Bottom Line Up Front
Rust and Bend 2 enforce memory safety without a tracing
garbage collector, yet they occupy complementary layers of the modern
systems stack. Both languages track resource lifetimes at
compile time. Rust uses ownership and borrow checking
(&T, &mut T, 'a), while
Bend 2 uses an affine dependent type theory (BendTT) where
live variables are consumed at most once (bendtt.lean).
- Choose Rust (
rustc,cargo,rayon,tokio) for OS daemons, network services, CLI tooling, zero-copy file parsers, and latency-critical loops over flat contiguous buffers (Vec<T>,HashMap<K, V>). In our matched 15-iteration Linux x86-64 DevSecOps policy benchmark, a native Rust binary executes in 2.05 ms with 2.62 MB peak RSS. Bend 2’s native binary follows closely at 3.11 ms and 2.66 MB peak RSS (DevSecOps benchmark). - Choose Bend 2 (
bend -o,LAWS.bend,PROOF.bend) for recursive divide-and-conquer trees, spatial hierarchies, cellular automata, and state machines requiring automatic GPU parallelism or formal inductive proofs. Doing the same in Rust requires thousands of lines ofunsafecode, CUDA/WGSL shaders, or external verification harnesses (Kani, Verus, Aeneas). On an Apple M4 Max, Bend 2 scales one functional source file across 16 CPU cores and Metal GPU warps to achieve up to 123.9x GPU speedup (0.063 svs.6.776 ssequential C) and verifies 3,200 generic proof instantiations in 0.38 s (benchmark dataset). - The Production Hybrid Pattern: Use Rust as
the perimeter I/O and systems shell (CLI parsing,
serde_jsondeserialization, network sockets, process supervision) and Bend 2 as the verified parallel compute kernel or differential test oracle (beads_bend).
1. Generational Context: From Rust-Based HVM2 to Bend 2’s BendRT
Understanding how Bend 2 compares to Rust starts with HigherOrderCO’s own compiler history:
- Bend 1 / HVM2 (2024): The original Higher-Order
Virtual Machine (
HigherOrderCO/HVM, 11,345 GitHub stars) was implemented in Rust and CUDA (HigherOrderCO/HVM). While HVM2 scaled recursive trees across NVIDIA RTX 4090 warps, reducing every arithmetic expression through heap-allocated graph nodes made single-core execution slower than native Rust or C (benchmark dataset). - Bend 2 / BendRT (2026): Bend 2
(
bendlang/bend, 23,353 GitHub stars) replaced dynamic graph reduction with BendTT (an affine dependent type system mechanized in 20,981 lines of Lean 4) and BendRT (bendlang/bend). The Bend 2 compiler (bend2/comp.ts) compiles.bendsource into a single unified C/CUDA/Metal file (bend prog.bend -o prog) with unboxed machine scalars (U32,F32), tagged 64-bit pointer words, and deterministic compile-time deallocation (heap_free) (benchmark dataset).
2. Empirical Hardware Benchmarks: Bend 2 vs. Native Systems Code
2.1 DevSecOps Promotion Gate Latency & Memory (Linux x86-64)
We ran a 15-iteration empirical benchmark evaluating four concurrent
container promotion policies under Linux cgroup isolation
(jobs.slice, Nice=10). Native Rust and native
Bend 2 delivered nearly identical systems footprints while beating
Python 3.14 by an order of magnitude (DevSecOps
benchmark):
| Runtime / Implementation | Mean Latency | Median (p50) | Peak RAM (RSS) | Speedup vs. Python | Source |
|---|---|---|---|---|---|
| Rust Custom (Native Binary) | 2.05 ms |
1.99 ms |
2.62 MB |
14.8x |
DevSecOps benchmark |
Bend 2 (bend -o Native Binary) |
3.11 ms |
3.09 ms |
2.66 MB |
9.8x |
DevSecOps benchmark |
| AWS Cedar (Rust SDK Binary) | 9.57 ms |
9.02 ms |
10.93 MB |
3.2x |
DevSecOps benchmark |
| Python 3.14 (Interpreter) | 30.36 ms |
30.47 ms |
15.18 MB |
1.0x |
DevSecOps benchmark |
Both Rust (2.62 MB) and compiled Bend 2
(2.66 MB) start in under 4 milliseconds and consume less
than 3 MB of resident memory. Neither language loads a virtual machine
or garbage collector at runtime (DevSecOps
benchmark).
2.2 Apple M4 Max Suite (16 Workloads: Native Sequential vs. Bend 2 Parallel)
Across the 16 official Apple M4 Max benchmarks in
/data/bend-ecosystem.json, sequential C
(clang -O3, representing the single-thread ceiling shared
by sequential Rust) runs within 0.70x to 1.50x
of sequential Bend (SEQ-CPU) on 14 of 16 workloads. Bend
2’s multi-core (PAR-CPU) and GPU (PAR-GPU)
backends then scale automatically without a single thread or shader
annotation (benchmark
dataset):
| Workload | Category | Native C (-O3) |
Bend SEQ-CPU (RSS) |
Bend PAR-CPU 16c (RSS) |
Bend PAR-GPU Metal |
GPU Speedup vs. SEQ | PAR-CPU vs. Native C |
|---|---|---|---|---|---|---|---|
| Conway’s Game of Life | Cellular Automata | 6.776 s |
7.803 s
(2.1 MB) |
0.647 s
(2.7 MB) |
0.063 s |
123.9x |
10.47x faster (source) |
| N-Body Physics | Particle Gravity | 5.126 s |
5.758 s
(2.2 MB) |
0.516 s
(2.7 MB) |
0.059 s |
97.6x |
9.93x faster (source) |
| Mandelbrot Set | Complex Plane | 3.750 s |
4.473 s
(2.3 MB) |
0.395 s
(2.9 MB) |
0.057 s |
78.5x |
9.49x faster (source) |
| Merkle Tree | Cryptographic Trees | 3.423 s |
4.222 s
(130 MB) |
0.422 s
(131 MB) |
0.071 s |
59.5x |
8.11x faster (source) |
| 3D Raytracer | Computer Graphics | 3.646 s |
4.616 s
(2.1 MB) |
0.396 s
(2.6 MB) |
0.151 s |
30.6x |
9.21x faster (source) |
| Procedural Terrain | Simplex Noise | 2.198 s |
2.225 s
(2.1 MB) |
0.197 s
(3.3 MB) |
0.106 s |
21.0x |
11.16x faster (source) |
| Breadth-First Search | Graph Traversal | 3.585 s |
3.918 s
(2.0 MB) |
0.343 s
(2.7 MB) |
0.207 s |
18.9x |
10.45x faster (source) |
| Levenshtein Edit Dist | Dynamic Prog. | 2.002 s |
2.559 s
(2.0 MB) |
0.236 s
(3.1 MB) |
0.144 s |
17.8x |
8.48x faster (source) |
| Tree Bitonic Sort | Sorting Networks | 5.719 s |
6.043 s
(146 MB) |
0.799 s
(156 MB) |
0.450 s |
13.4x |
7.16x faster (source) |
| Parallel Radix Sort | Sorting Networks | 2.791 s |
4.083 s
(651 MB) |
0.445 s
(617 MB) |
0.314 s |
13.0x |
6.27x faster (source) |
| K-Means Clustering | Machine Learning | 2.062 s |
2.069 s
(23.5 MB) |
0.268 s
(24.1 MB) |
0.191 s |
10.8x |
7.69x faster (source) |
| Tree Matrix Multiply | Quadtree Algebra | 2.964 s |
2.064 s
(2.8 MB) |
0.226 s
(14.8 MB) |
0.231 s |
8.9x |
13.12x faster (source) |
| N-Queens Solver | Combinatorics | 3.599 s |
5.406 s
(2.0 MB) |
0.455 s
(2.5 MB) |
0.933 s |
5.8x |
7.91x faster (source) |
| Symbolic Regression | Genetic Prog. | 2.208 s |
3.014 s
(2.1 MB) |
0.266 s
(3.1 MB) |
0.529 s |
5.7x |
8.30x faster (source) |
| HAMT Hashmap | Data Structures | 0.622 s |
2.741 s
(2.4 MB) |
0.238 s
(9.0 MB) |
0.521 s |
5.3x |
2.61x faster (source) |
| Regex Parallel Lexer | Text Processing | 1.036 s |
2.144 s
(2.0 MB) |
0.198 s
(3.0 MB) |
1.075 s |
2.0x |
5.23x faster (source) |
3.
Parallel Runtime Architecture: Rust rayon &
wgpu vs. the BendRT Task Cube
3.1 How Rust Parallelizes CPU and GPU Code
In Rust, CPU parallelism and GPU compute are two separate programming worlds:
- Multi-Core CPU (
rayon):rayon::join(f, g)and.par_iter()distribute closures across a thread pool using Chase-Lev work-stealing deques. The borrow checker verifiesSendandSyncbounds at compile time, preventing data races. However, recursive tree mutation in Rust often requires interior mutability (Arc<Mutex<T>>,RwLock<T>) or index-arena indirection (slotmap,petgraph) to satisfy borrow lifetimes across threads. - GPU Compute (
wgpu,cudarc,rust-gpu): Moving a recursive Rust algorithm to the GPU requires rewriting the algorithm from scratch as a flat array kernel in WGSL or CUDA C++. Engineers must flatten pointer trees into explicit index buffers, manage PCIe transfers, and tune thread-block shared memory manually.
3.2 How BendRT Parallelizes CPU and GPU Code from One Source File
In Bend 2, parallelism is expressed through the parallel
let (a b = f(x) g(y)), which compiles to the
BendRT Task Cube (bendlang/bend):
# Identical Bend 2 source runs on 1 CPU core, 16 CPU cores, or 16,384 GPU lanes
def sum(d: U32, i: U32) -> U32:
match d:
case 0:
i
case d:
a b = sum(d - 1, i * 2 + 0) sum(d - 1, i * 2 + 1)
a + b
Under the hood, bend2/comp.ts compiles this function
into a lock-free two-phase runtime (bendlang/bend):
- 64-Bit Tagged Term Words: Every Bend value is
represented as a 64-bit word
(
[rfc(1) | tag(7) | aux(16) | loc(40)]), packing machine scalars (U32,F32) directly into the word with zero heap allocation. The runtime maps an 8 TiB unified virtual address space (MAP_NORESERVE) shared across CPU and unified-memory GPU cores (benchmark dataset). - The 128 × 128 Task Cube
(16,384 Ring Queues): Instead of work-stealing deques, BendRT
organizes execution into a grid of 128 × 128 = 16, 384 lock-free ring buffers
(
RING_LEN = 1024). - Bulk-Synchronous Grow and Work Phases:
- Grow Phase: Active threads deal independent
parallel forks (
a b = ...) breadth-first in round-robin order across columns of the Task Cube until every ring reaches capacity. - Work Phase: All 16 CPU threads or 16,384 GPU lanes drain their assigned column rings simultaneously with zero cross-lane locking and zero work-stealing contention.
- Atomic Join Delivery: When two child tasks
complete, an atomic fetch-sub
(
atomic_sub_explicit(..., 1) == 1) on the parent frame’sneedcounter immediately schedules the continuation (a + b).
- Grow Phase: Active threads deal independent
parallel forks (
3.3
Why Rust Beats Sequential Bend on hashmap and
lexer (and Where Rayon Wins)
The architectural trade-off between Rust and BendRT is visible in the bottom four rows of the benchmark table (benchmark dataset):
- Sequential Flat-Memory Advantage (
hashmap:0.622 snative vs.2.741 sBendSEQ-CPU): Rust’s standardHashMap(hashbrown) uses SwissTable SIMD probing over flat contiguous byte arrays, exploiting CPU L1/L2 cache lines. Bend’shashmapevaluates a persistent functional Hash Array Mapped Trie (HAMT) via 64-bit pointer indirection and affine reference-count decrements. Only when Bend fans out across 16 CPU cores (0.238 s) does it overtake single-threaded native code (benchmark dataset). - Heavily Unbalanced Trees (Rayon Work-Stealing vs. Static
Task Cube): BendRT assigns tasks round-robin during the Grow
phase and never migrates them during the Work phase. Heavily skewed
search trees (where one branch prunes at depth 2 and another descends to
depth 40) can leave GPU lanes idle. On CPU-bound irregular search with
highly skewed branch weights, Rust’s
rayonwork-stealing deques dynamically rebalance load across cores.
4.
Correctness & Verification: Borrow Checker + proptest
vs. LAWS.bend + PROOF.bend
4.1 What Rust Proves vs. What Bend 2 Proves
Rust’s compiler is a world-class static analyzer for resource and memory safety, whereas Bend 2’s compiler is a static analyzer for both affine resource safety and mathematical functional correctness:
| Verification Capability | Rust (rustc + proptest +
cargo-mutants) |
Bend 2 (BendTT + LAWS.bend +
PROOF.bend) |
|---|---|---|
| Memory & Lifetime Safety | Borrow checker (&T, &mut T,
lifetimes) |
Affine Usage Wall (variables used ≤ 1 time unless + /
Data) (source) |
| Data-Race Freedom | Send / Sync marker traits |
Confluence (Church-Rosser theorem proven in Lean 4) (source) |
| Deadlock Freedom | Not guaranteed (Mutex cycles and
channel deadlocks compile cleanly) |
Guaranteed by construction (zero locks, mutexes, or blocking channels exist) |
| Termination Checking | None (loop {} and unbounded recursion
allowed) |
Enforced via structural syntactic descent on inductive types (source) |
| Domain Invariant Verification | Empirical sampling (proptest, typically 256 to 10,000
random inputs) |
Universal inductive proof (for x: T {lhs == rhs}) over
all ∞ inputs in 0.38 s
(source) |
| Formal Verification Tooling | External tools required (Kani, Verus, Creusot, Aeneas -> Lean 4) | Built into the compiler (bend PROOF.bend --verdict)
with zero external dependencies |
4.2 Case Study:
beads_bend vs. beads_rust
A concrete production example of Rust and Bend 2 working together is
Dicklesworthstone/beads_bend,
the law-proved port of the br (beads_rust)
dependency-aware issue tracker graph engine to Bend 2 (benchmark dataset):
- In
beads_rust, graph cycle detection, topological readiness sorting, and dependency blocking rules are tested via unit tests and property-based generators (proptest). - In
beads_bend,LAWS.bendencodes those exact DAG invariants andPROOF.bendproves them by structural induction. No sequence of edge insertions can introduce a silent dependency cycle, and golden tests verify CLI parity withbeads_rust(beads_bend).
5. Production Blueprint: The Hybrid Rust + Bend 2 Architecture
Rather than replacing Rust with Bend 2 or forcing Rust to do inductive theorem proving, high-assurance engineering teams combine both languages across a clean FFI or process boundary (DevSecOps benchmark):
┌─────────────────────────────────────────────────────────────────────────┐
│ Rust Host Shell (Cargo / Tokio) │
│ - CLI & Env Parsing (`clap`), Structured Logging (`tracing`) │
│ - Zero-Copy Network & Disk I/O (`serde_json`, `rkyv`, PostgreSQL) │
│ - Mutable Flat Caches (`DashMap`, `hashbrown`) │
└───────────────────┬─────────────────────────────────┬───────────────────┘
│ │
1. Production Compute Path 2. CI Differential Oracle Path
(C FFI / `bend -o kernel.c`) (`proptest` -> `bend -o oracle`)
│ │
▼ ▼
┌───────────────────────────────────┐ ┌───────────────────────────────────┐
│ Bend 2 Parallel Kernel (C/GPU) │ │ Bend 2 Verified Reference Twin │
│ - Compiles via `bend -o` │ │ - Guarded by `LAWS.bend` │
│ - 16-core CPU / 16,384 GPU lanes │ │ - Checked in 0.38 s (`--verdict`)│
│ - Lock-free tree/DAG reduction │ │ - Catches edge cases in Rust │
└───────────────────────────────────┘ └───────────────────────────────────┘
When to Use Which: Engineering Decision Checklist
- Write pure Rust when:
- You are building network servers, database drivers, filesystems, CLI utilities, or embedded firmware.
- Your hot loop mutates flat contiguous arrays or hash tables where L1
cache locality and SIMD intrinsics dominate (
hashmap,lexer) (benchmark dataset). - Your concurrency model is asynchronous I/O (
tokio,epoll,io_uring) rather than pure compute reduction.
- Write Bend 2 (standalone or called from Rust) when:
- You want one readable tree, graph, spatial BVH, physics, or sorting
implementation to scale across CPU cores (
7.6xto12.1x) and GPU warps (10xto123.9x) without CUDA orunsafeRust (benchmark dataset). - You use AI coding agents to synthesize state transitions or parsers
(
toon_bend,beads_bend) and need a 0.38 s compile-time mathematical gate (LAWS.bend/PROOF.bend) that blocks hallucinated logic before production (benchmark dataset).
- You want one readable tree, graph, spatial BVH, physics, or sorting
implementation to scale across CPU cores (