Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Compiling Rust for .NET, using only tea and stubbornness (fractalfir.github.io)
175 points by tbillington on Aug 29, 2023 | hide | past | favorite | 65 comments


Tangentially related, I've written a barebones assembler for Android .apk files once (strictly speaking, the assembler is for .dex files, but it also comes with a set of tools to package and sign .apk files). It showed up to be surprisingly easy. I expected to stumble upon some blocker issue any time that would make it impossible for me to continue — but one just never materialized! It's written mainly in Nim and provides enough primitives to allow creating Java "stubs" for native .so libraries, so that .apk-s can be built in Nim WITHOUT JDK AT ALL. The Android NDK is still kinda needed/useful, though IIRC mainly for access to adb, and especially adb logcat (which you'll need A LOT for debugging if you try to use this contraption).

I'd love to One Day™ Rewrite It In Rust, so that we could write .apk-s purely using the Rust toolchain, just using a JNI library as appropriate, sprinkling the code with some proc-macro annotations where needed by the assembler (for stubs), and possibly adding some lines in a build.rs (for .apk packaging).

The .dex assembler itself is at: https://github.com/akavel/dali — you may like to check out the tests at: https://github.com/akavel/dali/tree/master/tests to see how using it looks like.

An example project with a simple .apk written purely in Nim (NO JDK) is at: https://github.com/akavel/hellomello/tree/flappy (unfortunately, given Nim's poor packaging story, it's most probably already bitrotten to the extent that it can't be quickly and easily built & used out of the box). I recorded a presentation about this for an online Nim conference — see: https://www.youtube.com/watch?v=wr9X5NCwPlI&list=PLxLdEZg8DR...


Amazing work.


Article is a little wrong about the current state-of-the-art in writing Rust bindings for .NET.

One can use Uniffi with the C# generator to get fairly automatic bindings. You still need to package it up, which is a bit of a pain.

Uniffi really is an awesome idea. I expect more and more Rust code for foundational shared libraries as a result.



I'd wager that would use P/Invoke, which is what OP is trying to avoid (having true .NET IL would make everything seamless).


That just automates the generation of the ffi bindings (not too different from autocxx). It’s entirely different from compiling “managed” rust code. It’s like using a C/C++ library with p/invoke vs using C++/CLI or Managed C++.


Not sure how this is in disagreement with the comment.


Looks like the OP is still in high school. Kudos to them for pushing through, and having fun with compiler internals.

I wish I had this level of dedication at that age...


Looks like a young prodigy to me


If one was to do this as something other than a "fun project", wouldn't it make more sense to do a CIL backend for LLVM? That way any language utilizing LLVM would get be able to target .NET, or am I completely misunderstanding how rustc and LLVM works?


I -think- that CIL being a bytecode-y language runtime that actually has things like an object model, going straight from MIR to CIL offers a ... higher fidelity translation, or so.

(I apologise for this being vague, but this isn't really my area so if I tried to get more detailed I'd rapidly go from "quite possibly wrong" to "definitely wrong")


From my understanding LLVM's intermediate language is at a "lower level" (which is the LL after all) than the .NET CLR (or the Java JVM), losing some higher level parts of type understanding and looking a lot closer to machine language. You'd have to reconstruct or synthesize a new understanding of the "lost" high level information to target them as an LLVM backend.

It sounds like Rust's internal MIR intermediate language is a somewhat closer level match to CIL.


I think these two have different use cases.

Adding a .NET backend to Rust could give you high-level two way interop.

Adding a similar backend to LLVM would let you use .NET target similarly to WASM in that you could compile pretty much any software (C/C++, Go, Rust, etc) and run it on any supported platform without recompiling (well, it would JIT). But you'd have to stick to C-level APIs.


I wonder if it could run on this Rust implementation of the CLR I wrote a few years ago: https://github.com/Leowbattle/clr_lite


That looks like a really interesting experiment! Did you ever do write up of your work? I’m curious how far you got.



If it’s any consolation, Microsoft itself has shipped production assemblies generated with bad IL (for the auto-generated bindings/interop between the Windows 10 SDKs and C#)! Code appeared fine and would run OK until you tried to either R2R or AOT a project depending on that DLL (and it was just a single entry point that was mangled, iirc).


Beware, the rustification has broken thru .net defenses :) Not sure if I ever find use for Rust in .net runtime (C# has more or less same capabilities), but congrats anyway. However I'd gladly welcome some lightweight compiled language with easy and powerful meta-programming and AST transformation capabilities.


C# as a language seems supremely underappreciated/misunderstood.

It seems like it should have higher adoption given the performance boost over JS on Node while being syntactically similar to TypeScript (not hard to adopt for teams already familiar with JS/TS).

Combined with pretty good tooling these days and DX (hot reload is a thing), I'm always surprised by its seemingly lackluster reception.


> while being syntactically similar to TypeScript

The guy who invented C# went on to invent TypeScript.

I've been working with C# for over 20 years. The big problem with C# in the early days was the ecosystem: an awesome language, awesome IDE, but limited libraries and bloated frameworks.

.Net Core fixed a lot of this: ASP Core works more like Express, where routing is declarative, and has no surprises. In contrast, the original ASP for .Net used reflection to infer routes at runtime, which was extremely fragile.

The way that NuGet works now is more like cargo / npm; but before that package management was either all DIY or unpredictable.

IE: Until .Net Core, you could argue that C# was a better language, but end up getting trapped in the shortcomings of the ecosystem. Now that the ecosystem is on par with Rust / Node, it's much better.

I do think there needs to be a way to smooth over the difference between sync and async APIs. Far too often the difference between an async and sync method is just copy/paste. There needs to be a way for async/sync to just JIT out to call either the sync or async method of the stream/socket/lowest level API.


Because of that lineage and syntactical similarity, I'm always surprised it's not more widely adopted by startups that need to extend beyond Node.

I've worked at one YC startup and interviewed with others. C# seems like the natural step after TS. But several were more interested in Go and Rust. Strange to me when C# seems more logical.


As much as I like C#, every time I'm on the job market, I end up taking a job in C#.

Rust's biggest advantage over C# is that it's framework-free. IE, you compile a working executable; nothing more is required.

What's harder to understand is: Will I be more productive using Rust compared to C#? (After dealing with the learning curve.) Will my code be "faster enough" to lower the cost of operations? (IE, a cluster of 5 servers instead of 15?)


Here in The Netherlands I've seen it extensively used (and I'm using it myself in some projects, though nowadays the bulk of my work is in Rust)


I was working at a YC startup which was re-writing a portion of their backend to address some scalability and performance issues. The team was already familiar with JS and TypeScript as the initial implementation was Node.

I suggested C# because of the similarity to TS syntactically while being multi-threaded and more performant for the use case but was amazed at the backlash.

It's interesting to me that many teams that are already comfortable working full stack with TS reach for Go or Rust instead of C#. I can understand Rust if a team is doing systems level programming, but C# is an easier lift than Go (IMO) for teams building APIs and apps who are already versed in TS because the paradigms are very similar (async/await, try-catch-finally, generics, inheritance, tuples, deconstruction, anonymous types, general syntax, etc.)


Yeah, I'm a huge fan of C# for web stuff. I'd take it over Rust any day, unless there are strong reasons to want a systems language.


C# really is a brilliant language, but all of the awful microsoft bullshit surrounding it ruins its image.


I’ve been using C# since 2001, before C# 2.0 and its generics rewrite and when J# was a promising star in Microsoft’s eye. There is no “Microsoft bullshit” surrounding the language any more. Microsoft runs it in production on Linux and the language (and runtime) has been transformed.

(If only we could first-class FreeBSD support…)


msbuild, entity framework, msal, visual studio and all the jank and bloat that comes with it, all microsoft bullshit which exists right now.


I don't get it.

- EF Core works great. We connected it to RDS Postgres in AWS with container instances running on T4g ARM instances.

- Our pipeline used the `dotnet` CLI to do all the builds on our local M1 MacBook Pros and in GitHub Actions on Linux runners. Want to build a .NET codebase? `dotnet build` from the CLI. Want to run it? `dotnet run`. Want to watch for file changes and hot-reload? `dotnet watch`. .NET is really, really streamlined right now. Better than Node at the moment (as a dev that works fullstack and has workloads on .NET and Node).

- Our team used a mix of VS Code and JetBrains Rider. Two devs started on VS Mac, but eventually we all ended up using VSC or Rider on Mac.

- Bloat is pretty minimal; really easy to build a console app or a web API that more or less looks like an Express web app.

Here's a 7 minute video demonstrating building a .NET web API on an M1 Mac and then pushing it into an x64 Alpine Linux container in Google Cloud Run: https://youtu.be/GlnEm7JyvyY


In my 20 some years of using .NET and C#, I don't think I've ever run into a case where I felt "this is some Microsoft bullshit".

It's continuously gotten better, but I feel that many folks still have an image of C# and .NET from back in 2003 rather than 2023.


in my 10 years of using .NET and C# i encounter microsoft bullshit most days, so i would bet money that you run into those cases all the time but just got used to it lol


if you've only used it on windows then you have constantly been running into the case of only using it for Microsoft bullshit...


I've been using it exclusively on an M1 Mac for the last 2+ years. I was just at a startup where the entire team was deploying into T4 Arm instances in AWS. Two developers started on Windows machines, but at the end, every developer was on a Mac.

I have some workloads that I'm developing on my M1 Mac that I'm containerizing and pushing into an x64 Linux runtime environment in Google Cloud.

I guess this is my point: a lot of misunderstanding and misconception about the state of C# and .NET.


What do you mean? It has great support for other platforms. I've been using it on Linux for as long as .NET Core has existed and it has always felt really natural and there are as much documentation for Linux as for Windows with the things I've been doing


Do you mean the .Net Foundation brouhaha a year or two ago around code ownership? Or Visual Studio, the product? Or simply that some people will never forgive Microsoft for embrace-extend-extinguish and as a result won't ever give any tech a chance of it originated from Microsoft?


The C# tooling is second to none. (I keep hearing rumors of native Visual Studio support for rust, but they never seem to pan out.)


Just like the Windows kernel is actually pretty good, as most of the kernel architecture and design decision predates Linux kernel by 20 years, which Linux kernel slowly incorporated in a form or another progressively.

Noticeable things such as employing hybrid monolithic-microkernel design/kernel modules/SMP/cross-platform capability existed in Windows kernel long before Linux is mainstream. An honorable mention would be the Job Object since Windows 2000, and it is the nephew of Cgroups that is a key component in the Linux Container scene. NTFS is also one of the most successful B-tree based transactional filesystem that has many hidden gems behind.

But Windows userspace things and most infamously Microsoft Office, and Microsoft's hostile and manipulative approach towards end-users makes the whole Windows thing very shitty, while I believe Linux is the other way round, the whole ecosystem is built around free and openness. In the end the tech for building the foundation of the Windows is great but the execution by the upper management is disastrous.

For C#, this is the first language that provided the now ubiquitous async/await asynchronous programming syntactic sugar to the masses. Before that, we have to use something called Begin/End pattern called APM (Asynchronous Programming Model) which is already foreseeing a CPS (Continuation-passing style) based async programming. The async/await pattern, or the state machine + futures approach quickly spread to ECMAScript, Rust and recently C++20.

Don't get me started with LINQ/PLINQ, expression tree (which is a cousin of LISP macro) and extension methods (Rust and D people should know it as mixin/traits and UFCS), which is bringing a life-changing SQL like data operation pattern, which not only runs on SQL (LINQ to SQL) but also for daily life programming. I'm very confident that LINQ predates and heavily inspired Java Stream and Rust iterator design, with Java Stream being a half-assed copy of LINQ and Rust a saner one.

Not only that, but C# lambda is also far better than Java where you can only use final variables in Java lambda, which is based on anonymous class generation (you will understand it once you turn on a Java decompiler), while C# lambda is implemented using something called "delegate", which is an analogy of "function pointer" to C/C++ and is even interoperable as a native code thunk with API marshalling. So, you can indeed store C# delegates into native function pointers and callback to C# from C++ later.

You also have first of its own FFI in C# with DllImport, and with the magic of JIT almost all C/C++/native method can be imported efficiently and directly without so much preprocessing unlike JNI/JNA in Java. No need to manage Java state and stuff in C++, just figure out the right ABI and structs, but those are up to the user to implement which is still closed under C#.

C# also have the right kind of reified generic that does take types into consideration (hence reified) unlike Java which does Type Erasure instead, and eventually making the "generic" type into nothing but a glorified Object and losing a lot of optimizations opportunity due to this loss of information.

Java only recently started to work on value type with Project Valhalla. C# already has it from the beginning.

But, Microsoft is so shitty that it binds .NET Framework to integrate with Windows heavily. They want you to stick with WPF/WCF, IIS, SQL Server and ASP.NET, which is cool in the beginning but barely evolves and is missing what others have in the long run. Plus, the hostile attitude of Microsoft towards open competitor such as Linux from the early days (remember that Microsoft once called Linux "cancer" but now tried to fully embrace it, while I'm not sure when will Microsoft extend and extinguish Linux), with a big contrast to Sun's Java (until the acquisition from Oracle, which today turned to become a hostile and threatening old Microsoft monster). As such, the development and ecosystem of .NET and C# in extension, is often being laughed at as Microsoft shut-in and the developers as Microsoft fanboys. The trend is even more pessimistic when Android adoption exploded, which uses Java as the foundation for software development. So this is why C# development staggered since 2014. There is no competition between Java and C# anymore, because Java already killed it. Barely anyone uses .NET at that point on.

.NET missed a lot of growing opportunities especially in China which is being ridiculed to this day despite many improvements over the years, although this is more of a political choice over technical choice since there are tons of Java developers everywhere in China, most of them are often hostile to C# developers because they are taught not to embrace Microsoft.

While Mono is an exception, and it once exploded with Unity Engine (but now replaced by IL2CPP), it is still a pretty niche market (well, .NET itself is already being marginalized as a niche), and I assert they must have been in the brink of getting sued by Microsoft a couple of times in the past 20 years by copying some key components of the .NET Framework. Still, the relative success of Mono in the cross-platform market is a good attempt into making Microsoft rethink their hostile strategy and is a key catalyst to gradually make .NET open.

So, Microsoft is essentially burying diamonds and gold and jewels upon piles and piles of shit. They totally have the right minds and the capability to pull off the most stunning, impressive and revolutionary tech, but there are simply too many idiotic managers that does little to no coding, with a heavier side on greedy marketing just for the quick bucks, to cockblock and kill off those innovative projects, much like the Google today.


In general, a really good write up on the strengths of C# (would you like to work on an article together? I've had one sitting in the back of my head for a while).

> But, Microsoft is so shitty that it binds .NET Framework to integrate with Windows heavily

However, this is my point: C# and .NET are sorely misunderstood. Yes, the .NET Framework is Windows-only, but .NET Core and beyond are not. For the last 2 years or so, I've been doing .NET exclusively on a Mac M1 and deploying to a mix of Arm64 and x64 Linux servers.


The bundling of .NET Framework with Windows held back C# for many years because it tied its support lifecycle to that of Windows.

The runtime changes needed to improve the language could not be made easily due to the need to support it for 10+ years.


Well, .NET Framework isn't really relevant anymore. It's obsolete.


I am not sure what the major issue is here.

Mono has been there for a very long time, and even gave life to Unity 3D.


I really love C#, but one thing I wish it had (that Rust does) is move semantics. In C#, if someone passes your function (such as a constructor) an array, you have no guarantee the caller won’t modify it underneath you. In Rust terms, you would have a mutable reference, but the caller also does. Sometimes this is desired, and would be usable in Rust with a Cell, but other times it’s not. This can lead to defensive copying of arrays by the callee.

If I could annotate a parameter with some kind of “move” keyword that would prevent the caller from using it again, that would be great.

“Frozen collections” and ImmutableArray<T> can solve this issue, but the latter is essentially just a defensive copy of the array, but in a special type. I'm not holding my breath that such a thing would ever be implemented; Analyzers will probably be the best we get.


I was going to say that Microsoft appears to have chosen to address this at the library level with brilliantly optimized frozen and immutable variants of the collections, but you beat me to it.

It probably would have been easier and cleaner to implement some form of `restrict` and `const` semantics (or maybe move, like you mentioned) than to work as hard as they did to come up with a still sub-optimal solution, but the performance they’ve managed to eek out of the frozen and immutable variants is to be commended.


Oh, for sure. Microsoft's dotnet team deserves massive props for the effort they've put into the runtime. As for why there's no `restrict`, `const`, or `move` semantics, it seems the runtime team is extremely averse to modifying the CIL's capabilities as it would be a breaking change; They'd rather have the library team add classes/attributes that the runtime recognizes and special cases.


Wouldn't this just be ImmutableArray or ReadOnlyCollection?

    > “Frozen collections” and ImmutableArray<T> can solve this issue, but the latter is essentially just a defensive copy of the array, but in a special type
OK. Or just declare your parameter as IEnumerable<>? This has the effect of restricting the operations on the incoming collection in the same way.


Obviously, if this is a processing function that iterates over the array and forgets about it, IEnumerable<T> or IList<T> (IReadOnlyList<T> to communicate intent) would be the better option.

My thoughts involved constructors. In those, sure, I could take IEnumerable<T> or whatever else there is, but if I want to store an array (or list) as a field in my class, I'd have to make a copy with ToArray() (and friends). Being able to "move" an array from the caller into the constructor (callee) would be nice.

ReadOnlyCollection<T> isn't actually read only, but just a wrapper around an array/list. IReadOnlyList<T> also isn't read only, but just restricts me from editing it. I can't edit the parameters, but the caller possibly could, and that's my issue.


    > I can't edit the parameters, but the caller possibly could, and that's my issue.
This seems more like a concurrency issue, then. If that's the case, it seems like the right answer is some synchronization primitive or perhaps using a `Channel<T>` to serialize the flow.


Sometimes it's concurrency, but most of the time it's that I want to know I own the array. I want to know that `_array[5]` will be the same, no matter when I access it (excluding intentional modifications by callee). For example, if I take `T[]` as a parameter to my constructor, I might think `_array[5]` will be the same, but nothing stops the caller from doing `Array.Sort(theParameter)` sometime later.

    // in one function of the caller's type
    _data = new int[] { 1, 2, 3, 4, 5, 6, 7 }; // could come from some data collection engine
    _dataTable = new(_data);
 
    // then, sometime later, in another function of the caller's type
    Array.Clear(_data); // reset for next iteration or something
    // data table now has an array of zeros if it didn't copy the data
This is just an example, and the problem is not only limited to arrays; Mutable classes can be mutated by the caller after the callee is given them. Basically, the issue is multiple mutable references. The only solution to the above problem is a defensive copy by the "data table" constructor. I would like the ability to say, "the caller cannot modify this reference anymore".

This is something Rust gets right, IMO. If I want the callee and the caller to share mutable ownership, RefCell<T> or Mutex<T> can be used, and the usage of such a type makes that clear. If I want thread safety, I can wrap the mutex in an Arc<T>. And, if I don't want shared ownership, a plain T can be used, and ownership passes into the callee. The issue is: in C#, without defensive measures, all objects are just T* with no ownership or thread-safety.


> OK. Or just declare your parameter as IEnumerable<>? This has the effect of restricting the operations on the incoming collection in the same way.

It does not work that way, because it is an `in` parameter, thus you can still accept any mutable type (including an array) which implements the essentially immutable IEnumerable interface you require.

Now if it was about a return value, it would be a different story.

edit:

Still what you suggest has its merits in the other direction, as it gives the caller a guarantee that the passed in collection will not be modified inside. Had to untangle broken code (without unit test when i got it) that was called like something `CalculateCost(SomegraphData input)` and while its name (and xmldoc) did not suggest, it did subtle modification to the data it got handed in... I was very upset about that legacy codebase I just inherited when I found that...


I too really love C#. That said, C# biggest weaknesses IMO are all around a lack of proper const-like markup. Given that TypeScript (another language by the same designer) exhibits similar weaknesses, I've always interpreted it as an intentional weakness introduced by the language designer.

Working in a fully const-correct codebase in C++ is a joy. Working in a partially const-correct codebase in C++ is a nightmare because everything has to work around the semantic expectations of everything else.

Anders Hejlsberg, and those who took over the C# language design after he moved on to TypeScript, were certainly aware of how to make the language fully constable. The fact that they didn't leads me to believe they viewed it as a trade off between how much benefit do you get from using it vs how much cost do you take on from having that markup need to be everywhere in your entire language ecosystem. It's not enough for one application architect to say they want to take it on. Every engineer working on every library and every potentially reused function would have to take it on, because constness done right either tendrils everywhere or is a lie, and there are big costs to extending those constipation tendrils, just as there are big costs to not having them.


I’m apparently one of the few that use rust and C# as my language duo of choice; our company has gone all in on both. I think the more common combos are golang/rust, js/rust, or python/rust.

But proper support for discriminated unions (and perhaps something better than the emasculated match blocks known as switch expressions) cannot come soon enough for C# to enter the big leagues.


What’s this company, if we may ask?


NeoSmart Technologies. Our GUI and web stuff is C# and we’ve been migrating our low-level C and C++ code to rust (no_std rust for most of the C stuff). Some of our existing C/C++ stuff is extremely low level (think bootloaders, virtualization tech, etc) but also cross-platform and we’ve found rust to offer great ergonomics (not to mention safety) without an impedance mismatch under those constraints.

We’re also using rust for cli utilities and non-client-facing backend server stuff.


Thank you. You make interesting stuff.


Thanks! None of it is currently particularly in vogue, but it certainly satisfies the research and chasing rabbits^W gremlins down tunnels itches.


I guess hi )


I thougth to myself that surely there would be a CIL backend for LLVM, and why didn't the author just use it? But amazingly there doesn't seem to be.


I personally would have been surprised to learn that such a thing existed! As a C# and rust developer who has hacked on llvm before, I have to admit that these two languages (and their underlying techs/stacks) are absolutely worlds apart and there is so little overlap between their communities.

I’d have been less surprised if there were a llvm backend for C#, but that wouldn’t exist without an IL LLVM target (because you’d be limited to the language without any (standard) library support.

The first-pass Roslyn compiler is really naive when it comes to optimizations; I constantly marvel at how little optimizations are performed in its first stages compared to what llvm does (the jit is amazingly well-tuned, however). An LLVM backend for C# would make for very interesting learning and research opportunities!


LLVM have MSIL translator back in 2007 [1], it was abandoned die to lack of interest.

1. https://discourse.llvm.org/t/msil-backend/8480


From the linked GitHub repo:

> As for the heap allocated objects, they will be allocated from unmanged(non-GC) memory, and will be allocated/freed exactly like in Rust.

I understand this decision, but it would also be interesting to see a version of this that hijacks the global allocator and the alloc types to use the GC instead (while still allowing you to opt-out and use unmanaged memory).

Good work nonetheless!


.NET has three main types of pointers:

1. unmanaged pointers (C# syntax: T*, C++/CLI syntax: T*): these are the same as C pointers: can be converted to/from integers, cast arbitrarily, pointer arithmetic can be used. The garbage collector ignores these. These pointers can point to the stack, to native allocations. They can also point to the GC heap, but the GC won't adjust the pointer if it moves the underlying allocation (but allocations can be temporarily pinned).

2. object references (C# syntax: "T" (where T:class), C++/CLI syntax: T^): these are references pointing to the start of an object on the GC heap. They cannot point to the stack or to unmanaged memory. The garbage collector will update these as allocations are moved. Pointer arithmetic is not supported.

3. interior pointers (C# syntax: "ref T", C++/CLI syntax: T%): these references can point to the GC heap (including into the interior of objects), or to the stack or unmanaged memory. If pointing into the GC heap, the garbage collector will update these as allocations are moved. However, managed references can only live on the stack. It is not possible to store these on the GC heap; and certainly not possible to store them on the unmanaged heap (the GC wouldn't know to update them). Pointer arithmetic is supported, but conversions to integers are not.

It's not possible to translate Rust references to object references, because Rust references can point to stack or to the interior of objects. It's not possible to translate Rust references to interior pointers, because Rust references can occur on the heap, not just on the stack.

So a garbage collected version of rust is not possible without significant restrictions to the language (or using a GC more flexible than .NET's).

In addition to the limitations of the pointer types above, there's also an issue with enum types: .NET doesn't have discriminated unions. But the GC needs to be able to read the discriminator to tell if the enum contains pointers that need to be tracked by the GC.


> .NET doesn't have discriminated unions

Class hierarchies are discriminated unions. .NET doesn't feature general unboxed discriminated unions (although it can do this for simple blitted types using [FieldOffset]):

https://sourceforge.net/p/sasa/code/ci/default/tree/Sasa.Bin...


Yes, I supposed you could compile rust to .NET if you boxed everything (including simple integer fields, to allow taking their address as &i32) and used inheritance hierarchies for enums. Though that approach will still fail as soon as you encounter unsafe code with pointer casts, so I doubt you would be able to use the standard library.


TL;DR

> Besides, we don't want to be worse than the C++ people, do we ;)?


Rust for .NET, I did not believe it ha




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: