SERS vs Burst/DOTS/ECS — Why SERS Sidesteps The Problem
The DOTS Pain
Unity DOTS/ECS adoption is low single-digit percentages despite 7+ years of development. Why:
Burst restricts C# to a C-like subset:
- No classes, no strings, no managed arrays, no exceptions
- No virtual dispatch, no delegates, no LINQ, no async
- No
try/catch, no reflection, no boxing - Must use
FixedString32Bytesinstead ofstring - Must use
NativeArray<T>instead of arrays - Must use
FunctionPointer<T>instead of delegates (massive boilerplate per callback) - Must use
SharedStatic<T>for any static data (requires creating a key type per field)
ECS forces a total architecture rewrite:
- Everything becomes components (unmanaged structs) + systems
- No MonoBehaviours, no familiar patterns
- Entity Command Buffers for structural changes (add/remove components) — heavy boilerplate
- Sync points stall all worker threads
ISystem(fast, unmanaged) vsSystemBase(convenient, slow) — must chooseSystemAPIis source-generated magic that makes code confusing to read- Generic
IJobEntitydoesn't support generics
The result: Developers report ECS code is 2-5x more verbose than equivalent MonoBehaviour code. Most Unity projects don't use DOTS at all.
SERS Views Are Already What DOTS Components Want To Be
A SERS view:
public view Location {
public double Population;
public double Food;
public double Water;
public double Gold;
}
This desugars to a blittable struct — LayoutKind.Sequential, only primitive fields, no managed types. It IS a DOTS component in terms of memory layout, but without IComponentData, without archetypes, without chunk management.
Comparison:
| Property | ECS Component | SERS View |
|---|---|---|
| Memory layout | Blittable struct | Blittable struct |
| Managed types allowed | No | No |
| Needs registration | Yes (IComponentData) | No (discovered from compiled assembly) |
| Archetype management | Engine manages chunks | Host passes pointers directly |
| Adding/removing at runtime | Structural change + sync point | N/A (views are just data shapes) |
| Access pattern | SystemAPI.GetComponentRW<T>(entity) | @this.Food |
SERS Templates Are Already Stateless Functions On Data
A SERS template:
template<building> Farm {
const double BuildCost = 50.0;
bool CanBuild() {
return @this.Gold >= BuildCost && @this.Population >= 10;
}
void OnBuilt() {
@this.Food += 10.0;
}
}
This is what DOTS wants systems to be — stateless logic operating on data through typed references. But without:
- No
ISystemorSystemBaseboilerplate - No
EntityQueryconstruction - No
EntityCommandBuffer - No sync points
- No job scheduling ceremony
@this.Food += 10.0vsSystemAPI.GetComponentRW<Location>(entity).ValueRW.Food += 10.0
Why SERS Gets Burst-Like Performance Without Burst Restrictions
Rust fork (current)
Already compiles to native code via LLVM — the same backend Burst uses. But with full Rust language features: closures, generics, pattern matching, traits, strings, error handling. None of Burst's restrictions apply because the compiler produces native machine code directly. There is no IL, no JIT, no GC.
SERS Rust already achieves what Burst achieves — zero-GC native LLVM code operating on blittable data — but without stripping the language down.
C# fork (proposed)
Two performance tiers:
Tier 1: Normal C# (JIT or NativeAOT)
Template methods compile as normal C#. Full language. GC exists but is minimal because:
- View structs are stack-allocated or host-owned (not GC-managed)
- Templates are stateless (no heap allocation for the template itself)
@this/@from/@rootare refs to host-owned memory, not GC objects- The main GC pressure comes from string operations and temp allocations in logic
For most games this is fast enough. Unity's Mono is 2-5x slower than modern .NET, but NativeAOT closes the gap to near-native.
Tier 2: Burst-compatible hot path
Because SERS views are blittable and templates are stateless, template methods that only do:
- Math on view fields
- Call game-std APIs (which are themselves operating on blittable data)
- Read constants
- Use control flow (if/else, loops)
...are already in the HPC# subset. The forked compiler could emit [BurstCompile] on methods that stay within Burst restrictions. Automatic Burst compilation for qualifying template methods.
The game developer wouldn't need to think about Burst. The compiler decides: "this method only touches blittable data and calls safe APIs → mark it Burst-compilable."
What SERS Avoids
| DOTS/Burst Problem | SERS Equivalent | Why It's Not A Problem |
|---|---|---|
| Must rewrite all code as ECS components + systems | Views + templates | Views are just structs. Templates are just classes with methods. Normal code. |
| No classes in Burst | Templates desugar to classes but operate on blittable data | The class is a compile-time wrapper. At runtime it's function calls on struct pointers. |
| No strings in Burst | Views don't have strings. Logic CAN use strings. | View data is blittable. String ops happen in non-hot-path code. |
| No exceptions in Burst | Template methods can use exceptions normally | Only matters if Burst-compiling. Normal path uses standard C# exceptions. |
NativeArray<T> instead of arrays | Entity queries use host-provided batch arrays | The host (C#) manages entity collections. Scripts get refs to individual views. |
FunctionPointer<T> boilerplate | Interface dispatch or vtable (already the template dispatch mechanism) | SERS's vtable/interface dispatch IS function pointer dispatch, but the compiler generates it. |
SharedStatic<T> for static data | Template constants | Constants are compile-time. No runtime static access needed. |
| EntityCommandBuffer for structural changes | No structural changes exist | Views are fixed shapes. The host manages entity lifecycle. |
| Sync points stall threads | Host controls when to call into scripts | Evaluation is host-driven. No background jobs to sync with. |
ISystem vs SystemBase choice | No choice needed | Templates compile to whatever the target requires. |
| 2-5x more verbose code | @this.Food += 10.0 | Scope access replaces SystemAPI.GetComponentRW chains. |
The Architectural Insight
DOTS/ECS and SERS solve the same problem — how to efficiently operate on game data at scale — but from opposite directions:
DOTS approach: Take C#, strip away everything that prevents optimization (classes, GC, virtual dispatch, exceptions), force developers to restructure their code as data + systems, then hand the result to LLVM.
SERS approach: Design the data layout up front (views = blittable structs), write normal code that operates on that data (templates), let the compiler handle the optimization (LLVM for Rust, JIT/NativeAOT/optionally Burst for C#).
The difference is who does the work:
- DOTS: developer must manually write Burst-compatible code
- SERS: compiler produces optimizable code from normal-looking source
Implications For The C# Fork Product
The view restriction is the key
If views are restricted to blittable types (primitives, fixed buffers, other blittable structs), then:
- All view data is Burst-compatible by construction
- All view data is NativeAOT-compatible by construction
- All view data can cross FFI boundaries without marshaling
- All view data can be stored in unmanaged memory (no GC)
- Host can store views in DOTS-compatible NativeArrays if desired
The one new thing from the previous design document: views CAN have managed types in the C# fork (strings, arrays, references). But for performance, you'd want to keep views blittable. This could be:
- A compiler warning: "view field
string Nameis managed — consider using a localization key instead" - A compiler flag:
--strict-viewsenforces blittable-only - Or just convention: game developers keep views blittable because they understand the trade-off
Template methods and Burst
The forked compiler knows which methods only touch:
- View fields (blittable)
- Constants (compile-time)
- game-std functions (can be annotated as Burst-safe)
- Math operations
These methods could be automatically marked [BurstCompile]. The compiler does the analysis. The modder writes normal C#.
Methods that use strings, allocate, or call managed APIs compile normally (JIT/NativeAOT). No error, no restriction — just different perf tier.
No DOTS dependency
SERS does NOT require Unity DOTS/ECS. The host can use MonoBehaviours, GameObjects, ScriptableObjects — whatever they want. Views are just structs passed by ref. The host decides how to store and manage them.
But if a studio IS using DOTS, views are already compatible. The host can store views in NativeArray<LocationView> and pass refs to template methods. SERS and DOTS can coexist without friction because views are blittable.
Summary
| Question | Answer |
|---|---|
| Does SERS need Burst? | No. Rust fork already compiles to LLVM native. C# fork uses NativeAOT or optionally Burst for hot paths. |
| Does SERS need DOTS/ECS? | No. Views are plain structs. The host manages entity storage however they want. |
| Can SERS work WITH Burst? | Yes. Views are blittable. Template methods that stay in HPC# subset can be Burst-compiled. |
| Can SERS work WITH DOTS? | Yes. Views can be stored in NativeArrays. No conflict. |
| Does SERS avoid DOTS boilerplate? | Yes. @this.Food += 10.0 instead of SystemAPI.GetComponentRW<Location>(entity).ValueRW.Food += 10.0. |
| Does SERS avoid Burst restrictions? | Yes. Template methods are full C# by default. Burst-level optimization is optional and automatic for qualifying methods. |
| Why does this work? | Views are blittable by design. Templates are stateless by design. This IS data-oriented programming — the compiler just hides the ceremony. |