# SharpLib and general coding guidelines ## 0. PERFORMANCE. Title it 0. AXIOM: HIGH-PERFORMANCE / ZERO-ALLOCATION * **Zero Allocation Default:** Assume all code runs in a 60hz+ game loop or high-throughput pipeline unless marked `[ColdPath]`. * **NO LINQ:** `using System.Linq;` is strictly forbidden in core logic. Use `for` loops, arrays, or `Span`/`ReadOnlySpan`. * **NO Hidden Closures:** Do not use lambdas or delegates that capture local variables. If a lambda is necessary, make it `static` and pass state explicitly. * **Struct Semantics:** * Pass readonly structs using `in` or `ref readonly`. * Do not pass `struct` to interfaces unless constrained by generics (`where T : struct`), to prevent boxing. * **String Allocation:** NO string interpolation (`$""`) on the hot path. Use static strings, `string.Create`, or format into pooled buffers. * **Async/Task Overhead:** Default to synchronous execution for immediate state changes. If async is mandatory on a hot path, use `ValueTask`, never `Task`. * **Collections:** No `List.Add()` inside tight loops without pre-sizing the capacity. Prefer array pooling (`ArrayPool.Shared`). ## 1. CORE PHILOSOPHY * **Leaky Abstractions:** All abstractions are always leaky. Do not hide complexity. Expose failure modes, costs, and "reason" parameters. * **Visual Cost:** "Expensive things must look expensive." No hidden RPCs. Use explicit Message structs and `Send` methods instead of Rpcs * **Fast & Introspectable:** Code must be highly performant (hot-path aware) but deeply debuggable (`log`, `DebugOld`, `reason` strings). These are there to make debugging from console or log file possible ## 2. NAMING & SEMANTICS * **Leaf Libraries:** Core libs (`io`, `imm`, `net`, `log`) are 2-5 chars. **NEVER** include using {namespace}; for core libs or any short namespace * **No Redundancy:In Names** * **No "Get":** `Player()` not `GetPlayer()`. * **No Echo:** `Send(msg)` not `SendMsg(msg)`. * **No "I" Prefix:** Interfaces are `Renderer`, not `IRenderer`. ## 3. LOGGING (`log` static class) * **Constraint:** **NO** `Console.WriteLine`, `Debug.WriteLine`, or `ILogger`. * **Mechanism:** The logging system is very fast. It only queues the log on the main thread. It collects the caller debug info, and uses the directory name of the file for a default category (this can be overridden) * **Standard:** `log.info`, `log.debug`, `log.warn`, `log.error`. * **Finer grained:** `log.trace`, `log.high` * Use log.exception( ex, $"[what was trying to be done]" ); * **Introspection:** `log.props(obj, "Header")` and `log.exception(ex, "Context")`. * **Information** put important info as far to the left as possible, even at the cost of poor wording ## 4. IMMUTABLE STATE (`io`, `imm`) * **Rule:** Objects inheriting `Versioned`, `Recorded`, `Timed` are **IMMUTABLE**. * **Change Pipeline:** MUST use `imm.Process`. * **Ref Helper (Preferred):** `imm.Process(ref _state, s => s with { X = 1 }, "Reason");` * **Instance:** `_state = _state.Process(s => s with { X = 1 }, "Reason");` * **The "Hole Punch":** Always propagate a `string reason` parameter in your methods to feed the `imm.Process` log. * **History:** `obj.DebugOld` is for **DEBUG ONLY**. Do not base program logic on it. ## 5. Visual Cost * Network/IO/Expensive operations MUST NOT masquerade as local function calls. Require explicit structural allocation. * **No RPCs:** Do not make network calls look like functions. * **Pattern:** Construct Struct -> Send. * *Bad:* `proxy.Move(x,y)` * *Good:* `Net.Send(new MoveMsg(x,y))` ## 6. FEW-SHOT EXAMPLES (Strictly Imitate) ```csharp // ** NAMING & LOGGING // Explicit 'log' usage, no 'Get', no 'Console' public void Init() { log.startup( "log/current_project.log", log.Endpoints.All ); var waitTime = 1.0f; log.info( $"Waiting for {waitTime}" ); try { obj?.SomeOperation(); } catch( Exception ex ) { //Logs the exception name, message, the reason, the stack log.exception( ex, $"SomeOperation failed" ); } // ** IMMUTABLE PROCESS // Reason "Init" passed down. Ref pattern used. imm.Process(ref _state, s => s with { Ready = true }, "Init"); } // ** LOGIC FLOW public void Update(float dt) { // 'Player()' not 'GetPlayer()' var p = Player(); // Visual Cost: Explicit allocation of message struct if (p.Active) { Net.Send(new HeartbeatMsg(dt)); } } // ** "Punching a hole" with the reason parameter public void Equip(Item i, string reason /*No default so a reason will be passed in*/ ) { imm.Process( ref inv, s => s.Add(i), reason); } . . . // Somewhere else in project public void PlayerSwappedWeapons( Player pl ) { Equip( _item, $"Player {pl.Name} swapped weapons (PlayerSwappedWeapons)" ); } ```