Bend 2 vs. C# & .NET: CLR Task Parallel Library & Managed Heaps vs. the 128x128 Task Cube
An architectural comparison of C# 13 / .NET 9 (CLR, Task Parallel
Library, PLINQ, Span<T>, and ILGPU) against Bend 2’s
64-bit word runtime, GPU offloading, and 0.38 s proof checker.
Executive Summary: Bottom Line Up Front
C# and .NET 9 offer one of the fastest managed application
runtimes in existence, combining Span<T>, value-type
struct layouts, Native AOT, and the
async/await Task Parallel Library (TPL) for
enterprise web APIs and Unity/Godot game scripting. Yet when
algorithms shift to massively parallel recursive trees, GPU compute, or
formal verification, .NET’s CLR heap and work-stealing thread pool face
structural limits.
- Choose C# & .NET 9 (
ASP.NET Core,EF Core,Unity) for enterprise HTTP/gRPC backends, Windows/cross-platform desktop apps, game engine scripting, and SIMD pipelines over contiguous arrays (Vector256<T>,Span<T>). - Choose Bend 2 (
bend -o,LAWS.bend,PROOF.bend) when your workload is recursive divide-and-conquer tree/graph compute, GPU-accelerated simulation, or formally verified domain logic. Unlike CLR reference types (which carry a 16-byte object header), Bend 2 packs every value into a 64-bit word and runs 12 M4 Max benchmarks in 2.0 MB to 2.8 MB RSS. It also scales recursive code to 123.9x GPU speedup and verifies 3,200 generic proof instantiations in 0.38 s (benchmark dataset).
1. Memory & Value Representation: CLR Reference Types vs. BendRT 64-Bit Words
C# gives developers explicit control over value types
(struct, readonly record struct) versus
reference types (class, record). However,
recursive data structures (binary trees, ASTs, BVH scene graphs,
dependency DAGs) cannot be represented as inline value types in C#
because a struct cannot recursively contain itself without
heap indirection:
- Recursive Trees in C# Require Heap Reference
Allocations: Representing
abstract record Tree; record Node(Tree Left, Tree Right) : Tree;allocates each node on the managed CLR garbage-collected heap with a 16-byte object header (ObjectHeader+MethodTable*) plus two 8-byte pointers (32 bytes per binary node). - BendRT’s 64-Bit Word Packing: In Bend 2, every term
is a 64-bit word (
[rfc(1) | tag(7) | aux(16) | loc(40)]). Scalars (U32,F32) and unary variants (Leaf{x}) occupy zero heap bytes. Binary nodes (Node{l, r}) occupy exactly two 64-bit words (16 bytes total) and are freed immediately upon pattern match (heap_free) without waiting for a Gen0/Gen2 CLR garbage collection sweep (bendlang/bend).
2. Parallelism & GPU Offloading: .NET TPL / PLINQ / ILGPU vs. the BendRT Task Cube
| Parallel Dimension | C# 13 / .NET 9 (Task.Run,
Parallel.ForEach, ILGPU) |
Bend 2 (a b = f(x) g(y), BendRT) |
|---|---|---|
| CPU Parallelism Model | CLR ThreadPool work-stealing queues (Task,
ValueTask, PLINQ). |
128 × 128 Task Cube (16,384 lock-free FIFO rings) with bulk-synchronous Grow and Work phases (source). |
| Data-Race Prevention | Manual discipline (lock, Interlocked,
ConcurrentDictionary); shared state can race. |
Guaranteed race-free by Church-Rosser confluence and affine variable lifetimes (source). |
| GPU Execution Target | Requires third-party MSIL-to-PTX transpilers (ILGPU,
ComputeSharp) restricted to flat struct
arrays. |
Native f!(x) GPU offloading: compiles
recursive algebraic trees directly to Metal and CUDA (source). |
| Formal Proof System | Legacy Code Contracts retired; no dependent types or compile-time equational prover. | Built-in LAWS.bend and PROOF.bend verified
in 0.38 s (bend --verdict) (source). |
Apple M4 Max Benchmark Reference (Bend 2 CPU & GPU Scaling)
Across recursive workloads where .NET’s PLINQ is
CPU-bound and ILGPU/ComputeSharp cannot
offload recursive reference trees, Bend 2 scales one source file across
16 CPU cores and Metal GPU warps (benchmark dataset):
| Workload | Category | Bend SEQ-CPU (RSS) |
Bend PAR-CPU 16c (RSS) |
Bend PAR-GPU Metal
(RSS) |
GPU Speedup vs. SEQ |
|---|---|---|---|---|---|
| Conway’s Game of Life | Cellular Automata | 7.803 s
(2.1 MB) |
0.647 s
(2.7 MB) |
0.063 s
(16.7 MB) |
123.9x (source) |
| N-Body Physics | Particle Gravity | 5.758 s
(2.2 MB) |
0.516 s
(2.7 MB) |
0.059 s
(16.8 MB) |
97.6x (source) |
| Mandelbrot Set | Complex Plane | 4.473 s
(2.3 MB) |
0.395 s
(2.9 MB) |
0.057 s
(16.9 MB) |
78.5x (source) |
| Merkle Tree | Cryptographic Trees | 4.222 s
(130 MB) |
0.422 s
(131 MB) |
0.071 s
(17.5 MB) |
59.5x (source) |
| 3D Raytracer | BVH Graphics | 4.616 s
(2.1 MB) |
0.396 s
(2.6 MB) |
0.151 s
(17.0 MB) |
30.6x (source) |
| Tree Bitonic Sort | Sorting Networks | 6.043 s
(146 MB) |
0.799 s
(156 MB) |
0.450 s
(17.0 MB) |
13.4x (source) |
3.
Side-by-Side Code: Parallel Tree Sum & Inductive Proof
(C# 13 vs. Bend 2)
In C# 13, parallelizing a recursive binary tree sum with
Task.Run spawns heap-allocated state machines on the CLR
thread pool and provides no compile-time proof of algebraic laws:
// C# 13: Heap-allocated record classes + Task.Run thread-pool scheduling
public abstract record Tree;
public sealed record Leaf(uint Value) : Tree;
public sealed record Node(Tree Left, Tree Right) : Tree;
public static async Task<uint> SumAsync(Tree tree, int depth = 0) => tree switch
{
Leaf(var x) => x,
Node(var l, var r) when depth < 4 =>
await Task.WhenAll(Task.Run(() => SumAsync(l, depth + 1)),
Task.Run(() => SumAsync(r, depth + 1)))
is var res ? res[0] + res[1] : 0u,
Node(var l, var r) => await SumAsync(l, depth + 1) + await SumAsync(r, depth + 1),
_ => 0u
};
In Bend 2, a b = sum(l) sum(r) forks across 16 CPU cores
or Metal/CUDA GPU lanes via the Task Cube, and
mirror_involutive proves tree symmetry at compile time in
0.38 s (bendlang/bend):
type Tree:
case @Leaf:
val: U32
case @Node:
lft: Tree
rgt: Tree
def sum(t: Tree) -> U32:
match t:
case @Leaf{val}:
val
case @Node{lft, rgt}:
a b = sum(lft) sum(rgt)
a + b
def mirror(t: Tree) -> Tree:
match t:
case @Leaf{val}:
@Leaf{val}
case @Node{lft, rgt}:
l r = mirror(rgt) mirror(lft)
@Node{l, r}
def mirror_involutive(t: Tree) -> Tree{mirror(mirror(t)) == t}:
match t:
case @Leaf{val}:
finally
case @Node{lft, rgt}:
ih_l = mirror_involutive(lft)
ih_r = mirror_involutive(rgt)
rewrite ih_l
rewrite ih_r
finally
4.
Interop: Calling Verified Bend 2 Kernels from .NET 9 via
[LibraryImport]
Because bend kernel.bend -o kernel.c compiles to a
standard C11 shared library (libkernel.so /
kernel.dll), .NET 9 applications can invoke verified Bend 2
compute kernels using source-generated P/Invoke
([LibraryImport("kernel")]) with zero marshaling reflection
overhead (bendlang/bend).
Keep ASP.NET Core or Unity in C# for I/O and UI, and delegate parallel
tree reductions and LAWS.bend-verified state machines
(double-entry-ledger, merkle-tree,
raytracer) to Bend 2 (benchmark dataset).