Key Takeaways
- Started in 2001, the Mono project was the first initiative towards a multi-platform, open-source framework for .NET applications.
- Xamarin and Blazor represent Microsoft’s efforts on mobile and web applications (respectively), and both are based on and powered by Mono.
- .NET 5 provides two options of runtimes for users: the high-performance CoreCLR (for server and desktop applications), and the lightweight Mono (for mobile and WebAssembly).
- Mono still supports the .NET Framework compatibility mode, and it can be used with all of Microsoft’s .NET IDEs.
- While Mono is already a part of .NET, there are still developments focused on improving Mono’s runtime performance and garbage collection.
- Now that .NET Core can be installed in parallel with Mono, it is possible to evolve the language and runtime together.
Last year, Microsoft released its plans involving the future of .NET and the roadmap towards .NET 5. The next major release, scheduled for the end of this year, aims at providing a multi-platform, open-source framework and runtime built upon the best parts of .NET Core, .NET Framework, Xamarin, and Mono.
Microsoft’s movement towards open-sourcing .NET started in 2014, with the announcement that .NET Core would be open-source. However, much earlier than that, .NET already had an open-source initiative called Mono. Started in 2001, the Mono project was initially focused on establishing a .NET development platform for Linux desktop applications. The first official release was in 2003, and since then the project evolved towards supporting .NET in multiple platforms and operating systems.
Mono was being developed by Xamarin since 2011. Since the company’s acquisition by Microsoft and the following release of .NET Core 1.0 in 2016, Mono and .NET Core have been developed in parallel. In the light of the most recent releases, InfoQ interviewed Miguel de Icaza — currently at Microsoft, co-founder of Xamarin, and the original author of the Mono project — to talk about the current state of Mono, its future in the .NET ecosystem, and how Xamarin fits in this scenario.
InfoQ: Technically speaking, what are the main differences between .NET Core and Mono?
Miguel de Icaza: Mono was based on the .NET Framework — the big version of .NET that ships as part of Windows. Over the years, both Mono and .NET evolved to be used in different environments. In the .NET universe, this has culminated into the release of .NET Core 3 (which is the foundation for all future work and innovation), and the .NET Framework being the long-term maintained version that will continue to be fixed and tuned, but will not see any major innovation.
On the Mono side of the world, the runtime evolved to support what we called the "mobile profile," which was a curated subset of the APIs that was suitable for balancing the needs of users with the desire to make deployments of self-contained runtimes small. This served as the foundation of Xamarin’s .NET efforts, and the more recent WebAssembly work.
The different scenarios where .NET was being used, and the environments where they were used, fragmented the set of APIs that developers had to target. There was no simple way for developers to publish binaries of libraries that would work the same across all platforms.
The desire to create binary libraries that would work on all the various environments is the driving force for the creation of the .NET standard — a common surface of APIs that would work across all the different editions of .NET, from tiny devices and mobile systems to large servers. The approach we took here was to come up with a set of APIs that were present and worked equally across all platforms. But this still meant that we were maintaining different implementations of the libraries.
The way that we got all the variations of .NET to interoperate with each other was the .NET Standard, each new version of the .NET Standard has added more APIs that all the runtimes ensure are available across the board. The most used API contract today is the .NET Standard 2 which is supported across .NET Framework, .NET Core, Xamarin, and Mono.
A new 2.1 version of .NET Standard brought in new innovative capabilities, but is only available on Mono, .NET Core, and Xamarin — this is the first version of .NET Standard that is not supported by the long-term supported .NET Framework.
InfoQ: How is Mono positioned in the present state of the .NET ecosystem, considering the latest efforts involving .NET Core and the roadmap to .NET 5?
de Icaza: The short version is that with the upcoming .NET 5, users will have the same set of APIs available across all platforms, and will have a choice of a runtime (CoreCLR or Mono) and compilation system (static compilation, JIT compilation, tiered, or interpreted) to address the specific needs of their problem.
With .NET 5, we are unifying the implementation of the class libraries, yet providing two options of runtimes for users. At a high-level, we have a high-throughput, high-performance runtime in CoreCLR, and we have the lightweight, (but not as fast) Mono runtime. Each runtime has been tuned for the workloads where they have been used the most — CoreCLR, for server and desktop applications, and Mono, for mobile and lightweight uses, such as WebAssembly.
Also in .NET 5, we will have a unified runtime that can execute your C# or F# code on all the platforms that we support. On some of the platforms, users will be able to choose the runtime they want to use, and on other platforms, there will be a single runtime to use. For example, for desktop applications on Windows, only the CoreCLR runtime is suitable, and for iOS, only the Mono runtime is available.
Now, historically, Mono has had two execution and code generation engines. One, we called the "mini" code generator, and it produced native code very quickly, but also without many optimizations. For better optimizations, Mono has historically relied on the LLVM optimizing compiler. LLVM produces beautiful, optimal, and polished code,at the expense of compilation times.
Additionally, Mono has two modes of operation: one where the runtime generates code dynamically as it is executed (what we call JIT compilation), and one where we compile the code ahead of time (basically, a static compilation). The ahead-of-time (AOT) compilation system is used on platforms where dynamic code generation is not allowed (for example, iOS or video game consoles), or when improved startup performance is a must (some Android apps on low-end phones).
Mono can either run in pure JIT, mixed AOT/JIT, or AOT mode, depending on the requirements of the platform or the desires of the user. So, it is common to compile some of the core libraries ahead of time using LLVM to get the best code generated for those, while leaving the user code to be compiled dynamically (JIT), for example.
One downside of systems that require pure AOT is that the dynamic capabilities of .NET are not available (things like instantiating types dynamically, using the C# dynamic keyword, or loading code dynamically). So we set out to solve this problem.
In the last year, we have introduced a new execution engine and mode into Mono — an interpreter. The interpreter has turned out to be very useful, both because it has allowed us to bring dynamism (that was previously missing), and allows us to ship a small runtime to deploy to WebAssembly, as well as enabling us to implement capabilities, like Hot Reloading and Hot Restarting, for some of our users.
Once you have three engines with different configurations, it makes sense to bring a tiered-compilation system — one that allows the Mono runtime to dynamically adjust which code generation engine to use, depending on how the code is being used — and use startup time, memory usage, and long term performance. This is an active area of investigation and one where we want to tune the parameters, the learning, or surface the knobs to users to do so.
The nice thing about .NET 5 is that all of the capabilities of .NET 5 are available on all the platforms — users do not need to tune, or alter anything. The out-of-the-box experience has been already configured to match the best possible configuration across the board.
InfoQ: What is the difference between Xamarin and Blazor?
de Icaza: Xamarin was my startup that was focused on helping .NET Developers go mobile. And we used Xamarin as a brand for a spectrum of products, from developer tools, to online services. The latter group has been mostly folded into Azure DevOps at this point.
Xamarin developer tools included native SDKs and Xamarin.Forms. The native SDKs allowed developers to target Android and iOS, and use every native capability of those platforms from .NET. Xamarin.Forms is a cross-platform UI toolkit that allows developers to define their user interfaces once, and have the same code be mapped to the native idioms of the target platform.
Blazor is a new approach at building interactive Web Applications with C# by bringing some of the easiest to use and most-loved patterns of web development to .NET.
Developers build their Blazor apps and have a choice of where their logic runs — it can run on the server, powered by ASP.NET, or it can run fully on the client (and to do this, we run a .NET runtime inside the browser using WebAssembly). It is important to notice that supporting .NET on WebAssembly was done by Xamarin’s Mono team at the time, but the programming model was entirely conceived by the Blazor on WebAssembly development team. Mono only provided the means of executing their code.
InfoQ: Is it possible to use Mono with other Microsoft .NET IDEs (Visual Studio, VS Code, etc.)?
de Icaza: Absolutely. While most of the questions are forward looking as to what will come in .NET 5, today Mono is the engine that powers .NET on mobile, on Xamarin, or when you build Blazor applications that target WebAssembly. These are supported out of the box on Visual Studio and Visual Studio Code.
In addition to the officially supported configurations from Microsoft, Mono (as an open source project), still supports the ".NET Framework" compatibility mode, and this can be used with Visual Studio for Mac or MonoDevelop on Linux to build .NET Framework applications — and it is indeed how I do some of my spare time work, like TensorFlowSharp, TorchSharp (a binding of PyTorch for .NET), and gui.cs (a user interface system for building text user interfaces with .NET).
InfoQ: There are other frameworks related to .NET Core: EF Core, ASP.NET Core, etc. Are these frameworks compatible with Mono?
de Icaza: With .NET 5, they are all supported. Before .NET 5, things like ASP.NET Core do not work with Mono, mostly due to the tooling around it, rather than being a limitation of the runtime.
EF Core is a favorite tool of users who target mobile applications, for example — and this leverages the .NET Standard to run on Mono out of the box.
InfoQ: What is the future of Mono in the .NET ecosystem?
de Icaza: It has now graduated from independent effort, into being part of the whole of .NET. And now .NET will have a single distribution that targets every single platform we have accumulated over the years. I am very proud of the work of the open source community that supported the effort over the years, and the ongoing work of our team to integrate these VMs.
There are some fascinating developments taking place now. For example, just today I saw that Mono, when using static compilation and LLVM, can now match the performance of CoreCLR when running the TechEmpower benchmarks on our local configurations.
This is an important milestone for Mono, because when we started this effort, Mono was ridiculously far off — it was not even in the same ballpark. But we started to look at what was slowing down Mono, profiling, and measuring until we found most of the culprits and we got to this place.
Mono has historically had a precise garbage collector that is suitable for mobile devices, lightweight and efficient — but does not really scale well for these new computers with many CPUs and large memory subsystems. So, we have a prototype now of Mono using the CoreCLR GC — a highly scalable GC for Mono itself. I am hoping that we will be able to offer a GC choice to our users in the future.
Beyond that, the world looks more and more like a unified VM, supporting both C# and F# out of the box, and that is the most exciting piece of work ahead of us.
Up until now, evolving our languages and the runtimes together has been difficult, because evolving the runtime required evolving the runtime that ships on every Windows computer in the world. To avoid regressing a shared framework (shared by so many users), many risk mitigation processes were in place, and those prevented bold changes in this integration from happening.
Now that .NET Core can be installed in parallel, and can be upgraded at the cadence that the users need, we have a golden opportunity to evolve the language and runtime together — and you are starting to see some of those things show up. Capabilities, such as default method implementations in interfaces, and retrofitting the whole class libraries to work with nullable references are some of the recent developments,but there is so much more in store, and so many opportunities that have been unlocked because of this.
About the Interviewee
Miguel de Icaza is a Distinguished Engineer at Microsoft focused on the mobile platform where his team’s goal is to create delightful developer tools. With Nat Friedman, he co-founded both Xamarin in 2011 and Ximian in 1999. Before that, Miguel co-founded the GNOME project in 1997 and has directed the Mono project since its creation in 2001, including multiple Mono releases at Novell. Miguel has received the Free Software Foundation 1999 Free Software Award, the MIT Technology Review Innovator of the Year Award in 1999, and was named one of Time Magazine’s 100 innovators for the new century in September 2000.