Proposal: Introducing 'Spaces' - A Unifying Model for Concurrency, Isolation, and Performance #9710
-
SummaryThis proposal introduces a new, high-level architectural primitive for C# called a "Space". The core philosophy is to unify two historically conflicting worlds of programming into a single, cohesive platform: the productivity and safety of high-level managed languages (like C#) and the raw performance and control of low-level systems languages (like C++/Rust). The "Space" model aims to solve fundamental architectural challenges, most notably the classic "Monolith vs. Microservices" debate. It would allow developers to design and reason about a system with the simplicity of a monolith while enabling it to be deployed with the scalability and independence of microservices. I. The Core Philosophy & Problem StatementModern systems demand both complex business logic and high-performance data processing. Today, this often requires building polyglot systems, leading to increased complexity in communication (gRPC, REST), deployment, and developer skill sets. C# is a phenomenal language for productivity, but when absolute performance is needed (e.g., in a game engine's physics loop, a financial high-frequency trading model, or a data-intensive AI pipeline), developers often have to resort to C++ interop or separate services written in another language. The "C# Plus" vision aims to eliminate this trade-off. It proposes evolving C# to gracefully span the entire spectrum from high-level, managed business logic to low-level, unmanaged, performance-critical computations, all within the same language and project. II. The Foundational Concept: The "Space" ModelA Space is a completely isolated unit of computation. Think of it as its own "universe" with well-defined rules and a strict communication protocol for interacting with other universes. The "Harmony" Space: The Central Orchestrator
Core Characteristics (Applicable to All Spaces)
III. The "Logic Spectrum": Fine-Grained Space ConfigurationNot all tasks are created equal. The power of the Space model comes from the developer's ability to configure the execution characteristics of each Space declaratively, likely within the Configuration Dimensions:
Example Extended <Project Sdk="Microsoft.NET.Sdk">
<Space Include="BusinessLogic">
<Mode>Managed</Mode>
<Compilation>JIT</Compilation>
<Runtime>ThreadGroup</Runtime>
</Space>
<Space Include="PhysicsEngine">
<Mode>Unmanaged</Mode>
<Compilation>AOT</Compilation>
<Runtime>ThreadGroup</Runtime>
</Space>
<Space Include="ReportingService">
<Mode>Managed</Mode>
<Compilation>AOT</Compilation>
<Runtime>Isolate</Runtime>
</Space>
<DefaultSpaceCom Transport="gRPC" />
<SpaceCom From="BusinessLogic" To="PhysicsEngine" Transport="SharedMemory" />
</Project> IV. Syntax and Developer InteractionThe developer experience is paramount. The interaction with Spaces should feel like a natural extension of C#. Defining SpacesA Space can be defined for an entire file or for a specific block of code. // File-scoped definition
space PhysicsEngine;
public class Vector3 { ... }
public static class CollisionDetector { ... } // Block-scoped definition
space BusinessLogic {
public class OrderProcessor { ... }
} "Direct" or "Lambda" SpacesFor small, one-off, performance-critical operations, a // In a managed Space...
public double[] ProcessData(double[] rawData)
{
// Offload this heavy computation to a temporary, unmanaged, AOT-compiled Space
// for maximum performance, without the overhead of a formal named Space.
var result = direct(new SpaceConfig { Mode = Unmanaged, Compilation = AOT }) {
// This code block is now in an unmanaged context.
// It can't use managed types that require a GC.
// It would operate on 'rawData' after it's been marshalled.
// ... heavy processing ...
return processedData;
};
return result;
} Inter-Space Communication:
|
Beta Was this translation helpful? Give feedback.
Replies: 5 comments 5 replies
-
This feels like a runtime request (and an absolutely massive one) long before any actual language syntax should be considered. |
Beta Was this translation helpful? Give feedback.
-
I would be interested in a real world example of a program written in C++ and C# using all modern (Span) and classic features (unsafe), and the performance difference, and where that difference is coming from. |
Beta Was this translation helpful? Give feedback.
-
Thank you, @CyrusNajmabadi for the insightful feedback. I completely agree that the foundational runtime, library, and messaging primitives are the right place to focus the effort first. To facilitate this deeper, long-term discussion and to properly document the CScaf/Spaces vision, I have created a dedicated GitHub repository. I've migrated the full proposal to the repository's Wiki for easier navigation. To address the significant design challenges ahead in a structured manner, I have also opened the Discussions tab. Each major topic will be addressed sequentially, and I've started with a thread dedicated to the first and most critical area: the core runtime and library primitives you mentioned. I would be grateful if we could continue the detailed architectural discussion there. I look forward to hearing more of your thoughts. |
Beta Was this translation helpful? Give feedback.
-
The whole article is based on invalid assumptions and deprecated concepts.
This is the first invalid precondition. C# is high performance and sometimes outperforms C++, since it gets access to raw SIMD instructions. Marshalling data between two systems harms performance much more if both systems are high performance ready.
This is the deprecated concepts of AppDomain and .NET Remoting. They fail to provide a good safety or reliability even with old-school C#, and are suffering from severe security threats.
This is exactly what .NET Remoting and binary serialization did. It's been proven as fundamentally vulnerable.
Data marshalling will be the most performance-harmful operation. In the example code, how to pass the result array is very unclear.
Synchronization is very heavy and requires a lot of participation from the OS. Asynchoros operations should be used for I/O where is naturally a long latency, not high performance operations.
Not mentioning span making it non-sense for discussing performance.
Again, serialization is not safe by default. It must deal carefully with the data it can handle.
This is exactly the problem for P/Invoke and already handled by custom marshalers.
A very bad example. Using Moreover, the best for efficiency is to not marshal the data. P/Invoke tend to pin instead of copy data when appropriate.
This is what AppDomain provides. It didn't provide real safety but just made the CLR unnecessarily complex.
It's not secure by default. Any little oversight can break the entire safety. That's why coreclr abandons security concepts totally and relies on operating system.
This is not universal nor safe. Many objects can't be copied because it holds references to resources and others, and that's why
The entire discussion is based on ancient C#. Modern C# is going to provide more safety on already high-performance routines (#9705).
AppDomain has been shown as a wrong direction of approach. The proposal is not lightweight comparing to RPC-wrappers.
You can already achieve this today in C#, by writing everything in
The entire proposal is dealing a non-existent problem with deprecated concepts and unnecessary complexity. First, managed code isn't slow. SIMD instructions are used aggressively in the BCL, from the basic components like string. The JIT can switch aggressively for instruction set and do dynamic optimization with dynamic data, making it faster than unmanaged code. The work to rewrite BCL string/number routines from unmanaged to managed improved performance a lot. Even for cases when managed code isn't optimized enough, the marshalling overhead can easily be more than the performance difference. Marshalling gap between systems will also eliminate a lot of chance of optimization. |
Beta Was this translation helpful? Give feedback.
-
If our community were to spend time discussing pie in the sky ideas like a monumental change to the runtime and/ or C#, I think it would be better to concentrate on the long list of "warts" which people generally agree on. For example, array variance. It may sound small, but there are dozens of such things. And it's still a very open question whether or when such a project (restarting .NET) is actually undertaken. |
Beta Was this translation helpful? Give feedback.
Ok. Circle back once the core runtime, libraries, and other data/messaging primitives are hammered out. We can then see what might make sense at a language level at that point.