| Pretty much everything: > While C# does have AOT capabilities nowadays this is not as mature as Go's and not all platforms support it https://learn.microsoft.com/en-us/dotnet/core/deploying/nati... Only Android is missing from that list (marked as "Experimental"). We could argue about maturity but this is a bit subjective. > Go also has somewhat better control over data layout How? C# supports structs, ref structs (stack allocated only structures), explicit stack allocation (`stackalloc`), explicit struct field layouts through annotations, control over method local variable initialization, control over inlining, etc. Hell, C# even supports a somewhat limited version of borrow checking through the `scoped` keyword. > This is meant to be something of a 1:1 port rather than a rewrite, and the old code uses plain functions and data structures without an OOP style. C# has been consistently moving into that direction by taking more and more inspiration from F#. The only reasonable reason would be extensive usage of structural typing which is present in TS and Go but not in C#. |
That's sort of the problem with C#. It couples the type (struct vs class) with allocation. C# started life by copying 1990's Java "everything-is-a-reference". So it's in a weird place where things were bolted on later to give more control but still needs to support the all-objects-are-refs style. C# is just not ergonomic if you need to care about data layout in memory.
Go uses a C-like model. Everything is a value type. Real pointers are in the language. Now you can write a function that inputs pointers and does not care whether they point to stack, heap, or static area. That function can be used for all 3 types, no fuss.