Skip to main content

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 FixedString32Bytes instead of string
  • 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) vs SystemBase (convenient, slow) — must choose
  • SystemAPI is source-generated magic that makes code confusing to read
  • Generic IJobEntity doesn'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:

PropertyECS ComponentSERS View
Memory layoutBlittable structBlittable struct
Managed types allowedNoNo
Needs registrationYes (IComponentData)No (discovered from compiled assembly)
Archetype managementEngine manages chunksHost passes pointers directly
Adding/removing at runtimeStructural change + sync pointN/A (views are just data shapes)
Access patternSystemAPI.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 ISystem or SystemBase boilerplate
  • No EntityQuery construction
  • No EntityCommandBuffer
  • No sync points
  • No job scheduling ceremony
  • @this.Food += 10.0 vs SystemAPI.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/@root are 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 ProblemSERS EquivalentWhy It's Not A Problem
Must rewrite all code as ECS components + systemsViews + templatesViews are just structs. Templates are just classes with methods. Normal code.
No classes in BurstTemplates desugar to classes but operate on blittable dataThe class is a compile-time wrapper. At runtime it's function calls on struct pointers.
No strings in BurstViews don't have strings. Logic CAN use strings.View data is blittable. String ops happen in non-hot-path code.
No exceptions in BurstTemplate methods can use exceptions normallyOnly matters if Burst-compiling. Normal path uses standard C# exceptions.
NativeArray<T> instead of arraysEntity queries use host-provided batch arraysThe host (C#) manages entity collections. Scripts get refs to individual views.
FunctionPointer<T> boilerplateInterface 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 dataTemplate constantsConstants are compile-time. No runtime static access needed.
EntityCommandBuffer for structural changesNo structural changes existViews are fixed shapes. The host manages entity lifecycle.
Sync points stall threadsHost controls when to call into scriptsEvaluation is host-driven. No background jobs to sync with.
ISystem vs SystemBase choiceNo choice neededTemplates compile to whatever the target requires.
2-5x more verbose code@this.Food += 10.0Scope 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 Name is managed — consider using a localization key instead"
  • A compiler flag: --strict-views enforces 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

QuestionAnswer
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.