> Effectively once you want to write perf sensitive code in a garbage collectied language you have to stop writing idiomatic code for that language.
Only on GC languages that don't offer proper language features for value types.
Sadly most of them failed to gain market share, like Modula-3.
Eiffel and D are some of few around that offer such capabilities, and C# has been getting some love from System C# features, with spans, new ref types, and GC regions.
Yes, C# is slowly getting there (I'm a desktop C# dev since 14 years so I have waited for these features to creep in). Value types certainly help, but in idiomatic C# if you foreach over something you (sometimes) allocate an iterator on the heap. And it's not clear from the syntax when you do. You just have to know that a List<T> doesn't heap allocate its enumerator but most other types do, for example. These details are mostly hidden from you.
Using the low level features in C# (in the past structs, preferably in an AoS layout, then Span<T> etc tomorrow) will effectively make it a "Safe C". When you use those, you can't use idiomatic C (linq, heap allocs etc). You effectively agree to use a completely different subset of the language for your high perf tasks, and when you do, it doesn't look like the C# you have in the rest of your app.
We don't need types that mandate the same policy for every value, we need "this value is immutable" and then maybe hints about whether copying or aliasing is likely to perform better at each call site.
Only on GC languages that don't offer proper language features for value types.
Sadly most of them failed to gain market share, like Modula-3.
Eiffel and D are some of few around that offer such capabilities, and C# has been getting some love from System C# features, with spans, new ref types, and GC regions.