Hacker News new | past | comments | ask | show | jobs | submit login
Bflat: C# as you know it but with Go-like tooling (github.com/michalstrehovsky)
335 points by tate on June 25, 2021 | hide | past | favorite | 185 comments



I've been using C# with recent features like Function Pointers, [UnmanagedCallersOnly], Dotnet Native Exports, etc

Have been writing C# to interact with C/C++ and publishing C ABIs as static/shared libs that are natively compiled

My mind has been absolutely blown with what modern .NET and C# are capable of doing in terms of low level/systems program and interop with C/C++/Rust etc.

The performance and object sizes are killer too.

I think most people don't know or think C#/.NET are capable of this

Can envision a not so distant future where C# is a common choice for places when you'd typically reach for C++

Also, the folks on the .NET Interop team are all super friendly and willing to have a conversation with you or answer questions. My experiences with the whole .NET organization at MS as a random person has been nothing short of shockingly pleasant.


C# native interop is very, very nice.

However, the build/package system for this is still a complete mess if you want to target more than one architecture; I've spent much of the week looking at the question of how to make cross-platform assembly A depend on platform-specific assembly B, where B is one of B-win or B-mac, and it seems to require carefully hand building B into a nuget package.

I'm coming to appreciate msbuild, though. Or maybe that's Stockholm syndrome.


I second MSBuild as one of the best build systems I’ve had to work with. It absolutely has a learning curve but once you “get” how projects are evaluated and executed then you can start writing your own targets to do whatever you want.


MSBuild is very poorly documented. MSBuild is really not that good compared to what you get in FOSS land. I favor CMake over it, and personally I very much dislike CMake. The main thing in favor of CMake is you get cross platform.


The "core" of msbuild - targers, items, properties - is well documented. The actual work in normal cases is done by the vast hinterland of pre defined targets, and it's those that are badly documented. I've wasted several days reverse engineering 'ProjectReference' and only just found its detailed documentation. Fortunately you can read the source; unfortunately when you have to.

I think making it open source has come with a cultural change that's still propagating. It means not just defining the "Microsoft way" to do things but coping with myriad use cases turning up in the issue tracker.


If you think the "core" is well documented, link me the documentation which lays out all the built in targets involved in a standard c# project. Or even just a doc which describes the differences between PreBuildEvent, BeforeBuild, BeforeCompile, etc. As far as I can tell, this only exists as occasional comments in the .targets file. Msbuild documentation is horrible, without exception. When they occasionally document something it tends to miss half the optional flags and they never link the source code so it's up to you to find and correct it.


This is exactly what I"m talking about, usually I have to have Visual Studio generate a project file and see what it did.

Using XML as a general purpose programming language is also very ick.


You can write your build scripts in F# with the excellent Fake library or Cake for a similar C# DSL.

It gives you the same IDE experience for your build scripts and your code including REPL for experiments and a debugger when needed.

since it is .NET Core they are as cross platform as your other code.


I personally really like FAKE for anything .net builds.


> C# native interop is very, very nice.

Actually it was already there in J++, and now we have Oracle trying to add back what Sun killed in 2000, with keeping 26 years of history running, it is ironic how some things turn around.


the new slim SDK style csproj and the dotnet command replacement (maybe wrapper) for msbuild are great addition to come with .NET Core a while back. I think MSBuild and nuget are great compared to my experiences with linux rpm libwhatever or npm. I have worked on some moderately sized code bases (10s not 100s of projects in a solutions) and compile times stayed fairly reasonable.

I think the big downside is that the industry still thinks of .NET as stuck in .NET 2.0 or something, from my casual browsing that .NET is a skill not C#. Regardless, I'm getting kind of excited for .NET 6 on official release, and doing the migration of all our apps off framework to the latest and getting some getting the new lang version.


I would also be excited, unfortunely in what concerns Web development we never do everything from scratch, rather build on top of Sitecore, SharePoint, Dynamics, while destop stuff always ends up having some 3rd party commercial components like Telerik, ComponentOne, Office or VS Plugins,...


I don't know if by we you mean us C# users or the people you work with.

If it is the former I can say that I never ever built on top of Sitecore or SharePoint. Recently only Asp.NET Core or whatever it is called now.


Naturally us, the clients I work with.


I really like C# as a language, but as a Linux programmer, I found it difficult to install the dotnet sdk without the root permission. With that barrier, I can't recommend C# over Java, D or Go which are much easier to install.


> but as a Linux programmer, I found it difficult to install the dotnet sdk without the root permission

It’s a tarball. Unpack it wherever you like.

What exact problems did you have?

Edit: I’ve even “installed” the .NET SDK on ARM/Aarch64 devices this way. Zero issues.


The lack of the ICU library. As you mention it, I searched around and found setting "export DOTNET_SYSTEM_GLOBALIZATION_INVARIANT=true" could solve the problem. I stand corrected. Nonetheless, adding an env variable is still an extra step especially when the dotnet cli doesn't tell you what to do. An enduser has to google around to find the answer.


An "end user" will not install the SDK anyway. You do not need it to run .NET, it's for making your own apps.


An end user of an SDK is a developer that uses the SDK


>An enduser has to google around to find the answer.

Welcome to Linux?? Not to be sarcastic but if you want your hand held install Windows for your .Net development. It's pretty nice over there.


> Welcome to Linux??

Maybe more like, "Welcome to MS tools on Linux?" There are no similar issues with installing a JDK, for example.


The OP is complaining about needing root to satisfy som third-party library dependency (libicu) when installing the .NET SDK outside the system package-manager, with the tarball only.

I think that’s a pretty far fetched complaint. There are tons of software out there on Linux which will break if you don’t satisfy their dependencies.

I’m sure the OpenJDK-tarball has some system-wide dependencies too (libssl?), but you can’t tell that because you probably installed it as root, using a package-manager instead.

If you do the same with the .NET SDK (use root, install via package-manager) you will find everything working equally smooth.


I generally do install JDKs as root from the system's package manager. This is primarily due to the system integration that it provides.

However, I often keep a collection of older versions and different patch levels in my home directory. These work fine for testing with the non-openjdk distributions for compatibility purposes.

I wasn't familiar with the icu library issue, so maybe it is something straightforward, but it seems odd that the fix was an env var. I certainly wouldn't say something like "welcome to linux" because of a scenario like this.


> I often keep a collection of older versions and different patch levels in my home directory.

And they are obviously going to work because you’ve satisfied all the main OpenJDK dependencies through the install with your package-manager.

If you repeat your own scenario with the .NET SDK instead, you will have the exact same experience.


That's actually not true. They'd work even if I removed the main one.

Its how I did it before the distribution packaged OpenJDK, which really wasn't that long ago.


Have you installed jdk before? I installed jdk quite a few times without root and never had a problem. Jdk only depends on essential system libraries like libc. It ships other necessary libraries in the tar-ball. Do you have a reference to your claim that Java requires libssl?


> I installed jdk quite a few times without root and never had a problem. Jdk only depends on essential system libraries like libc.

The Ubuntu repos suggests there are more dependencies than just plain libc.

https://packages.ubuntu.com/hirsute/openjdk-11-jre

Could it be you have those dependencies satisfied through other things you’ve already installed?

> Do you have a reference to your claim that Java requires libssl?

None at all. It was an example of something I found it reasonable it might depend on, since .NET also depends on that on Linux :)


The package manager provided distributions tend to have different dependencies than the tarballs from Oracle.


You don’t need to install the SDK to run a dotnet core app. They can ship what’s required to run and there’s even single executable options now as well.


One caveat: If you ship a self contained app you often end up with 200MB of assemblies to ship. and the single file executables tend to load very slowly. It's basically an archive that first gets extracted and then executed. I had to give that up with a recent app because it was just too slow.


This hasn't actually been the case since dotnet Core 2.

Since dotnet Core 3, you can use assembly trimming to remove unused assemblies. That results in a package of around 10MB for a Hello World app, or more like 40-70MB for large, real-world apps.

From dotnet 5 there is also member trimming, which will trim unused parts of assemblies, which will further reduce the size. I haven't used this yet, but Microsoft claim it can result in packages 5x smaller than with assembly trimming, e.g. only 2MB for a Hello World app.

There is also AOT compilation, but I wouldn't hold my breath on seeing that become production-ready any time soon (Microsoft have been hyping it and saying it's "coming soon" for 10 years or so).


I just tried it on a small project of mine. It's 955 lines of C#[0], 6 dependencies, already configured for publishing a single file, self contained, for win-x64, ready to run. I built in release mode with publish trimmed, and trim mode set to link. The final size of the binary is 24.6 MB (not counting CLR DLLs), with a build time of 23.2[1] seconds.

I also have a Rust version of the project. 710 lines of Rust[0], 128 total dependencies in the tree, building in release mode with the MSVC Windows compiler. Final size of the binary is 2.29 MB, build time of 22.2[1] seconds.

Things are not great when your build times rival Rust's, and the output is slower and an order of magnitude bigger.

[0] Note that the C# version does have more robust handling when writing its output file than the Rust version, which adds couple dozen lines. Also the style conventions for brackets puts opening brackets on a new line for C#, the same line for Rust.

[1] Measured with hyperfine configured to run "dotnet clean -c Release" and "cargo clean" before each run.


FWIW, I reckon 25MB forba self-contained build is pretty good! Build times are annoyingly if you use trimming tho, I'll certainly agree there.

But Rust is such a very different beast than dotnet, that I'm unconvinced it's a useful comparison; IMO a better comparison would be Golang.


> not counting CLR DLLs

Why would you exclude those in this comparison - they're already (guaranteed to be) installed on your windows targets?

How about linux/Mac targets?

I think 20-30MB is quite good - puts it in the ballbark of golang.

2MB+ for rust actually sounds a bit big -that's stripped?


> > not counting CLR DLLs

> Why would you exclude those in this comparison - they're already (guaranteed to be) installed on your windows targets?

Note that this is a stand-alone build; it doesn't require the runtime to be installed. With that in mind, you're right they should be included, which would increase the build size by 8.3 MB.

> How about linux/Mac targets?

I can't build a Mac target because I don't have a Mac. I just built for a linux-x64 target in WSL, and the resulting binary is 35.0 MB. The Linux build looks like it's packaged the CLR into the main binary instead of keeping them separate, which would account for the greater size.

I did do a benchmark with hyperfine, which gave a 25.5 second build time. However, this is on WSL1 building off and on to an NTFS drive, which has known performance issues.

> I think 20-30MB is quite good - puts it in the ballbark of golang.

I've never used Go, but my understanding is that the Go compiler is very fast but doesn't do as much in the way of optimizations. If that's the case, having a larger and slower binary compared to Rust would be expected before you get to the packaged runtime.

The issue I'm taking here is that doing a trimmed dotnet build is (in this case) giving the same build time as Rust, but is only doing some AoT compilation and dead-code elimination. Rust is already doing that in addition to a whole host of other optimizations.

From a user perspective, this feels like dotnet is giving me a worse end product for the same time taken. Especially given the Rust version wasn't harder to write than the C# version (in fact, due to bad documentation the C# version was harder).

> 2MB+ for rust actually sounds a bit big -that's stripped?

No, that is not stripped, and with the standard release profile.


Maybe this is better for command line and server stuff. The app I was building used WPF with Core 3. The regular size was 180MB if built as self contained. Trimming took off maybe 30 MB but build times were painfully long. And the initial load took around 30 secs or more on some machine.


I haven't used WPF in 10 years or so. Come to think of it, I haven't done any desktop stuff with .NET Core at all - wow, 180MB is pretty damn big!

Just took a look at my current project, which has several components: an ASP.NET web UI is 80MB, an ASP.NET API is 65MB, and backend services range from 40-55MB (these are all pretty complex, production-grade components).


Yes, this deployment option makes tradeoffs that are clearly more in line with the use case of pushing out long-running server applications to machines with minimal configuration, rather than for desktop user applications.


That’s my impression too. Seems these days in general desktop applications are more of an afterthought in the .NET world and most new features are built mainly for server stuff.



Of all the possible ways to handle toolchains on Linux, I'm quite happy with asdf[1]. I've successfully built stand-alone fsharp/csharp "Hello worlds" off of dotnet via asdf - but I've not used dot.net in anger.

I chiefly like asdf because I typically need at least two toolchains (with various versions for various projects) - eg ruby and nodejs, or python and nodejs.

https://asdf-vm.com/

https://github.com/emersonsoares/asdf-dotnet-core


> The performance and object sizes are killer too.

> I think most people don't know or think C#/.NET are capable of this

Take all of this amazing stuff and it also works on embedded/raspi4... I have been playing around with using C#8 to directly drive & sample GPIO. Who needs timer ICs when you have a busywait while loop checking the high res timer...

Also, don't forget that you can go open an issue or submit a PR to any of the major .NET repositories right now, and expect to have your work (assuming accepted) incorporated into an official .NET release within a year or so.

And tooling, etc. Check out visual studio 2022. Its available in preview now.


> Also, don't forget that you can go open an issue or submit a PR to any of the major .NET repositories right now, and expect to have your work (assuming accepted) incorporated into an official .NET release within a year or so.

Yes! They also publish videos of their design review discussions - I submitted a cryptography-related PR a while back, and it was really cool to watch my proposal being discussed, and then even cooler when my code made it into dotnet :)

> And tooling, etc. Check out visual studio 2022

Don't forget JetBrains Rider - I switched from VS a few years ago, and haven't looked back. VS is great too, but in terms of performance and stability, Rider kicks it to the curb (IMO).


> Who needs timer ICs when you have a busywait while loop checking the high res timer...

A lot of people are concerned about power usage these days, particularly if these things are running off a solar cell.

And these days, most embedded controllers include some kind of timer anyway. Micropython has a timer interface that interrupts into a python subroutine. I use this for application level routines interfacing with a hardware watchdog.


Why couldn’t you do the same thing with C#? Being worried about power is fine and all, but I’d rather build the application and then analyze the actual performance and power draw to determine the appropriate solution for power efficiency. I’m sure there’s some WFI (wait for interrupt) available that could be used to solve this.


There's nothing wrong with C# -- as long as the tooling supports the processor you're targeting and the interrupt/sleep states of the micro.

If you're running off a battery say, then it's better to build your software from the start to optimize for the various sleep modes.

https://lastminuteengineers.com/esp32-sleep-modes-power-cons...


I like C# as a language. It's boring and gets the job done. But I will say I was disappointed after trying to set up a C# development environment on Linux after having such a positive experience with the language on Windows. It sounded like it was a reasonable thing to expect to work since apparently Microsoft supports Linux these days, but I couldn't see it through. When the official editor (MonoDevelop) is abandoned for a proprietary version with no notice on the homepage or docs, and all that people recommend you instead is to "just install Ryder", which costs a large sum, it's hard to not just want to go back to a language that has a more open ecosystem.


Working with C# on Linux isn't too bad if you use VSCode. You have to do a bit more manual work and it's not as smooth sailing as with Visual studio or visual studio for Mac but it gets the job done. I used it to work on an Aspose Words api for a reporting tool.

Scott Hanselman has a couple of guides on his blog on how to get it up and running.


VS code is not really that “open” either.

The on-by-default telemetry and license restrictions come to mind


This might be helpful.

https://github.com/VSCodium/vscodium

It is a repository of scripts to automatically build Microsoft's 'vscode' repository into freely-licensed binaries with a community-driven default configuration.


I believe the license for the VScode C# plug-in prohibits using it with VScodium.

I didn’t know this until recently when someone pointed it out.

https://github.com/dotnet/core/issues/505

Thought it was relevant since OP is talking about a Linux IDE for C#


Actually several of those features exist since version 1.0, because the CLR was designed to support languages like C++ as well, so there was always a way to access them even those that are only exposed after 7, but yeah bad M$.


Apparently the remark I made to how people lose good tooling due to needless religious hate was lost in the crowd, oh well, better improve my English skills.


The author’s ZeroSharp project is also interesting. It shows how you can compile C# without any runtime. No garbage collection, no exceptions. You can perform stunts like make a 5KB Hello World or a EFI application that runs with no operating system:

https://github.com/MichalStrehovsky/zerosharp

I did a survey recently of binary sizes for .NET apps and comparisons to other languages. Things like NativeAOT (on which Bflat is built) and Graal Native Image let these languages get down to a binary size , startup speed, and deployment model similar that enjoyed by Go and Rust developers.

https://github.com/AustinWise/SmallestDotnetHelloWorlds


> You can perform stunts like make a 5KB Hello World

Which, according to HN/proggit, is the only valid measure of a programming language. :)


If one could cross compile to something like an ARM-Cortex, 5k hello world with no GC would be very interesting.


I assume you mean an ARM microcontroller? I think it may be possible. .NET has a code generator for ARM32, which I think generates Thumb-2 instructions.

The trouble I had last time I tried (.NET Core 3.1 I think) is you needed a cross compiling versio of RyuJIT that has the same bitness of your target. That is , you needed one that ran on linux x86 targeting linux arm32. And that was not easy to find. Maybe if I try compiling from a Arm32 host it will be easier.


I’m not sure it would because a C one is measured in bytes and does the same thing.


a little off topic. has anybody tried using C# as a nicer C ? I tried using D(betterC) a while ago but I hit some compiler bugs that was annoying. I also tried Zig but compilation times is not preferable. I don't want anything better than C I just want nicer C and without header files and compiler bugs.


C# is a managed C++ (not to mix with the actuall one[1}), so why bother with C?

D better C mode is getting better with each version actually, even if there are some corners to fix.

[1] - https://en.wikipedia.org/wiki/Managed_Extensions_for_C%2B%2B


because it has all the pieces of the puzzle to turn into a C, like D that has a -betterC flag I hope that maybe they add something like that for C#.

I also hope you keep working on D(betterC) but for now I stick with C, generating C using bb(clojure) is also an option.


No source code.

> I'm not ready for people to see (or to accept pull requests) things that are specific to bflat. If you think bflat is useful, you can leave me a tip in my tip jar and include your GitHub user name in a note so that I can give you access to a private repo when I'm ready.

It's not hard to use CoreRT directly. [1]

[1] - https://github.com/dotnet/corert/tree/master/samples/HelloWo...


There's zero chance anyone will seriously consider using this without the source code being available. :) So I am not too worried. The author would be ending up shooting themselves in the foot if they keep it that way for long.


Shouldn't it be D flat instead?


Probably not? I think they are intentionally calling it the relative minor, not same note, which makes a kind of sense in the usual way punny names do (i.e. a bit of a stretch, but not ridiculous).


B♭ isn't the relative minor of C♯? I think that'd be A♯ minor.

Edit: Actually B♭ minor is the enharmonic equivalent of A♯ minor. IE another case of things in music that are the same but aren't.


I thought of adding the comment about enharmonics but it decided it would muddy the water further and edited it out. Should have left it in.


Enharmonic in the context of 12-tone equal temperament!

slowly backs away


Oh no you don't

And now I'm down the rabbit hole of reading about tuning systems again.


> We need a name that's witty at first but seems less funny each time you hear it.


I pictured Go = G.

If you want C# and G (a nasty tritone) together, then you need something else. Adding in a Bb will give a nice diminished chord.


No, because then "be flat" part would be lost.


>The source code is in the respective Roslyn/NativeAOT repositories. I'm not ready for people to see (or to accept pull requests) things that are specific to bflat.

hmm?

edit: nvm, it seems he's MS employee, so it's I guess it's legit.


> it seems he's MS employee, so it's I guess it's legit.

don't care about pedigree - no source, no trust for a compiler...


He's asking for patreon donations though, in that same sentence?


I feel Dflat would have been a better name.


Was about to comment the same thing.


This is nice, I have two questions if you don't mind:

- Can bflat be used to compile F# code?

- How do you build multiple files?


Not the author, but I would assume bflat cannot compile F# as this project uses the Roslyn compiler, which supports C# but not F#.


Pass the multiple files to `bflat build`. Or if you run `bflat build` without arguments, it will compile all *.cs files in the current directory. Not great, but works for now.


This is very interesting. I like C# as a language, and I like Go by its tooling. If this project goes well, it would be the best of both worlds.

The official `dotnet` command is not to my taste for a few reasons. It uses XML, and it is quite slow, e.g. a simple "Hello, world" project takes 2 seconds to launch every time. I mean, it always takes 2 seconds even after compiling everything prior to that. It might be acceptable for an interactive development environment that employes an auto-compiling workflow, but for a CLI tool, it is too much of a burden. I know Microsoft are trying to improve it, but at least up until now it hasn't been very successful.[1]

[1] https://github.com/dotnet/sdk/issues/8697


The discussion linked hits all the points; dotnet run is build+run, ie do a dependency scan. It even lists the faster alternatives.

On the other hand you have a point that "dotnet" is trying a bit too hard to be a magic swiss army knife.


`go run` is also build+run, with a dependency scan. But it executes instantaneously. So there is already an evidence that the status quo can be improved. Even Rust's `cargo run` is much faster than `dotnet run`.


Wouldn't bflat be the same note as a sharp, not c sharp? I'm not musically educated, but I don't get the name.


Yea, I'm about 20 years rusty on the scales but I thought d-flat was the same as c#, not b-flat...


Db and C# are "enharmonic equivalents". In 12-tone equal temperament, they're the same pitch, but in other tuning systems like just intonation they might be almost but not exactly the same pitch.

https://en.wikipedia.org/wiki/Enharmonic


12-tone equal temperament being what virtually all modern western music is transcribed in and what GP probably learned.


Yup, most likely what I learned and yet I'm still fascinated to learn more. Thank you both!


I was hoping to see in the readme how this is different than what they offer in core today? You can build self-contained exes (and they're getting better with each release). Is this the same only different or an improvement on that?


It is different.

.NET Core will create a self-contained executable which can have AOT compilation (or not), but which will include the byte code so that it can be JIT-optimized at runtime.

This is about creating a binary that is small and uses some of the upcoming experimental stuff like Crossgen 2 and NativeAOT. Some of the Crossgen 2 stuff will land with .NET 6 this fall.

As the project says, it's about bringing together two components that are being actively worked on in the .NET ecosystem to create a compiler and runtime for small binaries.

For most people, you'll want the normal .NET self-contained Ready2Run binaries. They're compatible with everything and rock-solid. But sometimes you want to play around with something - like creating C# programs that are going to be tiny.

Microsoft and others in the .NET ecosystem are improving C#/.NET at a rapid pace and it's great. bflat is, as it notes, using what is being created in that ecosystem. I mean, bflat literally labels itself "Initial proof-of-concept release" at this point. The guy writing it is on the .NET Runtime team at Microsoft and is really interested in these types of things. I think we can all imagine ourselves creating a project that does things a bit differently to figure out what is possible, figure out possible future directions we could take our work, etc.

So, it is different from what is available in .NET today. It's written by one of the people on the .NET Runtime team who is interested in this stuff. Some of the concepts might show up in .NET 7/8/9. Heck, Crossgen 2 should be showing up in .NET 6.

It's a cool proof of concept of slimming down C# binaries and even the readme shows how things like stack trace information takes up space.


Those self-contained exes need a .NET runtime to be just-in-time (JIT) compiled to code your CPU can actually run. This JIT compilation happens as your app runs, so your startup performance suffers as a result. On the other hand, bflat compiles your project ahead of time into native code your CPU understands.

Also, to build that exe you have to use the .NET SDK which pulls in lots of tooling: MSBuild, NuGet, etc... It looks like bflat ditches all of that.


You can actually add `-p:PublishReadyToRun=true` to your `dotnet publish` command and it will do AOT compilation for you. It blows up your executable a bit, but it does pretty much give you warmed up code at the get go.


That's only partial compilation and not the full AOT available with something like CoreRT.


It's been a few years, but I worked on a dotnet core C# project once. Prod was Linux and dev usually OSX. I remember running a dotnet build to generate some kind of artifact (dll maybe) that still needed the SDK to run. Is there some other way to do it that made a self contained executable?


Yes, .NET Core can now create self-contained executables. Microsoft and others have been enhancing this since it was introduced in .NET Core 2.1.

I've been enjoying the way that .NET has been evolving in pragmatic ways. The initial implementation basically created a self-extracting zip that would include the runtime. That had its drawbacks, but it was a way for them to get self-contained deployable out the door with minimal hassle. Sure, it meant taking up a bit more space, but it worked and solved what most people cared about: having a single file that they could run without needing to install things in the OS.

Likewise, they came up with ReadyToRun. Basically, they'd AOT-compile stuff for fast startup times, but include the byte code so that things could be JIT-compiled during runtime. This meant that the AOT-compiler didn't need to be perfect and that they didn't need to worry too much about things like the performance of reflection code. That code would end up JIT-compiled in long-running programs. Again, a pragmatic approach that does have some drawbacks (like large deployable artifacts), but they got it out the door and have been improving it as time goes forward.

A more pure approach might be to wait until one can produce a really top-notch AOT compiler, wait until one can replace certain reflection-heavy code, wait until one can optimize libraries, wait until one can do lots of testing to make sure you don't have regressions, etc. But that requires a lot of time while what a lot of people might want isn't a pure solution, but just something that allows them to speed up start times.

Likewise, zipping up the runtime with your code into a self-extracting and self-running file isn't the most pure approach, but it meant that you could get a single file to scp and just do `./myprogram` on.


The self extracting is gone for Linux in .NET 5 and gone for Windows in the upcoming .NET 6. If any copying still happens, it just within the memory space of the process.

If you include extra DLL or .so files, those still have to be extracted so that the operating system dynamic linker can load them.


Yep! It's one of the things that's nice about the .NET ecosystem. We didn't have to wait for self-contained executables and got them back in 2018 (even if it wasn't perfect, it worked well enough) and they refined it as time went along in a way that didn't require me to do things.

Microsoft could have waited until .NET 5/6 to offer self-contained executables "the right way", but they were able to create something that offered 90% of people what they wanted a few years earlier.


Yep. One of the things I've been doing lately with some internal utility apps is building a small Windows exe (for Workstations where almost always the dotnet runtime is already installed), and a larger but self-contained binary for linux.

    dotnet publish -r win-x64 -p:PublishSingleFile=true ---self-contained=false

    dotnet publish -r linux-x64 -p:PublishSingleFile=true -p:PublishTrimmed=true --self-contained=true
To give an example of this for a reasonably complex test tool I have on .NET core 3.1, the Windows exe is 3.7MB and the linux binary is 38MB. I'm guessing there's some room for optimization in the process though, as the linux binary is compressed (tgz) to 13.37MB.


The binary is that big on Linux because the debug symbols are embedded in the executable. You need to strip them.


In the interest of keeping the comment small, I omitted a couple things:

    -p:Configuration=Release -p:DebuggerSupport=false 
FWIW, I did also try the following, but found they had basically no impact on output size:

    -p:TrimMode=link
    -p:EnableUnsafeBinaryFormatterSerialization=false 
    -p:EnableUnsafeUTF7Encoding=false 
    -p:EventSourceSupport=false 
    -p:HttpActivityPropagationSupport=false 
(Tested on .NET Core 3.1.5)


Huh, the debug symbols are in separate .pdb files, aren't they?

38MB is a pretty typical size for a real-world, self-contained, assembly-trimmed package, and the size comes from the runtime itself, plus the core assemblies that weren't trimmed out.


Actually, in my tests with the AoT compiler I had to strip the binary to get a significantly smaller one despite there being a .pdb file. Your mileage may vary as the build flags can be a bit fiddly.


Yes, since I believe 2.1 you can make a self contained executable with sdk included using dotnet publish. You can read more about it here: https://docs.microsoft.com/en-us/dotnet/core/deploying/#publ...


The nice thing they also added was the ability to trim the self-contained app, so it doesn't include a lot of unnecessary assemblies.

https://docs.microsoft.com/en-us/dotnet/core/deploying/trim-...


self contained executables simply bundles the libraries, but still requires a JIT compilation to execute.

The description of bflat is what you are looking for, and it's the second section of the readme.

bflat implements a form of ahead-of-time compilation.

This is closer to .net native conceptually, but that was only a UWP abomination.

edit: replies have pointed out this is actually closer to ReadyToRun, a neat feature I was not aware of.


replied with this on another post, but you can add `-p:PublishReadyToRun=true` to your `dotnet publish` command to do AOT. it blows up your binary in size, but pretty much gives your warmed up code from the start.


it doesn't fully AOT your app and worse it doesn't produce a native static executable

it runs few tier for JIT, it still ship with IL and the JIT

don't advertise ReadyToRun as "hey we got AOT at home, says Microsoft salesman"

because all it does is makes me want to use Go instead, it feels and sounds bloaty


What about with ReadyToRun and single file?


Cool, so like Graal for Java. 2-3mb min file size is quite a bit smaller than the smallest Graal native images tho, I wonder what the difference is.


Can you do .NET development on a Mac these days? I vaguely remember a thing called Mono that was in vogue for a while before .NET Core became open source. Anyone have time to do a quick recap of capabilities on non Windows or Windows Server systems?


Been using a mac + rider at work for years now, at a very large company. Still have to fire up windows occasionally for Framework/Legacy stuff for though. I sometimes try out ideas in C#/F# at home (linux). With Rider, it’s pretty much the same experience on all 3 OSes, it’s pretty nice.


Yes, it all Just Works (TM). Rider with net5 is as seamless for me on a Mac as it is on Windows.


My whole company is c# and every single person has a company issued Mac, 0 issues.


Basically, the only major systems it not on are the BSDs, as the work is still in progress.


As one of the original contributors trying to land BSD-support back in the 1.0 days (2015!!! before life got in the way), that’s been the story for waaay to long now.

I really hope some day we finally land it. Even as a full time Linux-user these days, BSD still has a special place in my heart.


You can, but not all the languages receive the same level of support. I really tried (twice) to use F# on Mac recently and gave up because the tooling/docs didn't work.


How come? Most of the F# open source community is on Macs.

Were you using Ionide?


Yes! The thing you're looking for is .NET Core.


The latest release is just called .NET 5

.NET Core was the name for the cross-platform version, but that's the default now and will be the future. No need to differentiate from the older Full Framework anymore.


Microsoft naming strikes again. I suspect they're only dropping the "core" now because they can - below 4 there's a need to disambiguate versus .net Framework versions.


And the road between .net core 1 > .net core 2 > .net core 3 was extremely bumpy.


Not to mention there is no upgrade path from .Net Framework to Core. Major missing features like WCF are still an issue in .Net 6. Migrating is a long and slow processes. Luckily we can use .Net Standard 2.0 as a bridge for libraries.


Or features like how Assembly reloading and MSIL code generation works.


So is this a step down from c#?


A step and a half actually


This is exciting. Given the tiny size of the executable i would love to see this hooked up with Blazor for web applications. It also is very appealing for tooling.


The only suggestion I'd have is renaming it Dflat, especially fitting with the spiel around it being the same but different


Brilliant name.


> Brilliant name.

The name is a bit of a blunder:

1. Because of the placement of the ♭ in ♭Flat, that's actually read as "FlatFlat".

2. The note D♭ is the same as the note C♯.


It would be better as Bx (B double-sharp), which is enharmonic with C#


Just fork C, name it B#, and you're done.


> 2. The note D♭ is the same as the note C♯.

Well, actually...


I haven't played guitar in 20 years but I think D flat would have been a much better name


B flat (or A sharp) is the relative minor of C# major, so I think that is what they were going for.


There are products where B stands for 'be' in combination with 'gone'. So in a way it says "be flat" as a program invocation, it's not just about notes if you ask me.


This is how I interpreted it. "Be flat", as in, be as small as possible.


D is a programming language that's currently used, B is not.


Shouldn't it be Dflat?


B flat as a replacement to C# huh? That name is a bit too clever.


Jokes aside... Without C#, life would ♭flat


Clever name.


A little off topic, but what's so good about C# nowadays? All developers that touch it start preaching it around as the best programming environment that they've ever used, but I haven't seen that many projects written in C# that really impress me (like Java or Go excel at). Also, and maybe this is unfair, but Microsoft's software is known for being buggier than one would expect and I imagine that C# is used a lot there.

Please, help me correct my prejudices :)


> what's so good about C# nowadays?

For me, it basically has all the advantages of Kotlin over Java. ASP.NET is also a lot better than any Java web framework I've tried. It doesn't really have new concepts, but everything works together without spending time glueing things together. Things just build and run with minimal hassle. Rider and Visual Studio offer excellent tooling that doesn't stop at odd boundaries (think about how most template engines have poor IDE support in the Java world).

With Java, how do you create a data class? Are you making Java Beans (and hoping no one ever makes a mistake)? Are you using a library like Immutables to generate code at compile time? Are you using Kotlin for that and compiling two languages? Are you using the records feature which just landed (out of preview) three months ago and doesn't work the way Java Beans work? Are you using Lombok and installing IDE plugins and doing fun runtime crazy?

C# isn't perfect, but it has a lot of the modern things that a lot of people want that are available in languages like Kotlin. The tooling is first-class and the libraries from Microsoft work well.

.NET offers AOT-compilation that doesn't involve a lot of trade-offs (mostly just binary size which isn't that important to most people). GraalVM is really cool, but also changes the performance characteristics of a lot of Java code and requires the community to think about re-orienting how they write Java programs.

Go is a great language, but many people want more features than the language offers and that isn't likely to change.

> I haven't seen that many projects written in C# that really impress me (like Java or Go excel at)

If you're talking about libraries, it's likely that because you're not a C# dev you aren't looking at C# libraries. If you're saying, "well, I see Kubernetes in Go and Kafka in Scala/JVM, but I don't see any equivalent in C#/.NET," then yes: there are fewer large open source projects in C#/.NET. If I were writing your comment, I would have said, "I see fewer influential open source projects" rather than "projects that really impress me". You're probably not impressed by Kubernetes so much as you note that it is large and influential.

I think C#'s lack of representation here comes down to timing. .NET Core (the first cross-platform .NET) is only 5 years old. At the time, we didn't know whether Microsoft was really committed to .NET Core or if it was just an experiment. By contrast, Kafka is 10 years old and Kubernetes is 7 years old. Both of those influential projects literally couldn't have gone with C# and .NET because they started well before cross-platform .NET really existed (beyond the unofficial Mono effort which didn't offer the same performance or sanction from Microsoft).

If you're coming from the open-source, Linux-deploying side of the world, C# hasn't been an option very long. I would say that it started becoming clear 3 years ago that .NET Core was truly going to be the future for Microsoft.

How many influential open-source projects do you know of that started in the past 3 years? Probably very few.

Realistically, it will take a while for a lot of people coming from the Linux-deploying world to see C#/.NET as a viable ecosystem. It will continue to be viewed suspiciously by some people for a while. If you're looking for influential projects, they don't come along frequently. Hadoop, Spark, Kubernetes, Kafka, etc. are the kinds of things that you don't see every year.

I don't think it's a reflection on the language so much as a reflection on timing and culture. I think C# is still thought of as the Microsoft-only, Windows-centric ecosystem that it used to be. I think people looking to create an influential project know that the broader community will accept projects written in Go, but it's unclear whether the broader community will accept projects written in C# - many people might just be turned off due to their preconceptions. So when you start the next Hadoop, Spark, Kubernetes, or Kafka, do you choose C# and potentially alienate part of the community who write off your project due to preconceptions about the language?

Plus, there's a certain amount of inertia around some areas. Data science and ML are still heavily Python-based. It's not that Python is the best language for those things, but the community is familiar with it and so if you're creating a tool for that community you're going to make it in Python. If you make it in Go or Java, it will just languish without usage and without people improving it. Is that because Python is a better language for impressive data science and ML projects than Go or Java? I think it's more around community knowledge and perception (and the already built tools they might be familiar with and also want to use).

> Also, and maybe this is unfair, but Microsoft's software is known for being buggier than one would expect and I imagine that C# is used a lot there

Yea, that is just unfair. I've found C# to be so easy and seamless. No more headaches around builds, no more headaches about how to glue together Maven generating X while Hibernate expects Y while something else expects Z. I think part of it is that because C# was a Microsoft project for so long, the ecosystem didn't end up with as many camps in it. With Java there was Sun, IBM, and RedHat all kinda pushing similar yet slightly-distinct stuff. I think Java also fell into a problem where so many people tried to solve the "I just need a data class" problem that now we have a bunch of solutions that all act slightly differently and can lead to headaches.

Realistically, this assertion isn't disprovable. "Microsoft software is known for being buggier": is it? As someone who truly hated Windows for a long time, I would definitely have been on that train a while ago. Is their software today of worse quality? Realistically, I don't use Microsoft software much and never really have. I don't really think it's worth addressing this more than I already have since it wasn't really a fair criticism to begin with based on a potentially spurious premise.


Great comment. The only things I would add:

1. The seamless integration to things like containers (working with Docker Desktop is fantastic - and you can debug your code inside the container).

2. Razor pages. I gave up on hideously complicated SPA and use Razor now. The user experience is similar but it's a lot more secure generating everything on the server.

3. Deploy to AWS ECS or AWS Lambda with a few clicks. You need the AWS tools installed in Visual Studio but as a one man shop this is insanely productive.

4. Write it on Windows, deploy it on anything. The two use cases I use the most are things like Linux based containers but also ancient Windows servers in client environments where the infrastructure guys don't want to install new libraries. I wrote a small web slurping utility that had to be deployed on an old Windows Server 2012 machine and the self contained executable just worked without having to install anything else.

.NET Core has been fantastic for me.


The reason you don't see many projects written in C# is that there are far fewer open source C# projects than Java/Go/etc. Most C# is written in-house (enterprises, some startups (admittedly relatively few.))

I've been a .NET Dev for 20 years. C# keeps trucking along adding features at neck-breaking pace. That can be good and bad. Personally I wish F# had more resources assigned to it at MS. Having said that C# seems to be getting more and more F# features as time goes on.

I did a small amount of Java in my career, and learned golang on my own time. Neither clicked with me or swayed me to consider a move to full-time employment using those langs. I've been learning Rust most recently and I'm considering looking for a job doing Rust.


> Personally I wish F# had more resources assigned to it at MS.

This absolutely. Or that they had avoided the usual NIH MS is prone to, and just supported another ML variant (thus reducing the load to match the resourcing).


Other ML aren't compatible with the CLR type system. That was the main point of porting Ocaml to .NET.


Same problem with CL. But I can think of a better way to fix it :)


Background: I touched C# a little over 5 years ago writing ASP.NET MVC + jQuery apps and decided I hated it then.

About 6 months ago I had a side project where I took a C++ library and decided I'd try to translate it into every language that supports C/C++ Interop, to have a canonical "C Interop reference + comparison" repo for anyone interested

I found out that C# could do this, and started looking into how.

Long story short, it's now possible to use C# and .NET to directly interop with C/C++. Function Pointers, structs and all. You can publish a binary or static/dynamic library for any platform that's natively compiled -- zero dependencies.

It allows you to manually allocate memory and provide allocation strategies. Shit, you can even turn the GC off entirely (at this point the language is very barebones).

See ZeroSharp by same author:

https://github.com/MichalStrehovsky/zerosharp

So on top of this surprising viability for fairly low-level or native programming, it's also:

- Just generally good at everything/bad at nothing

- Blazingly performant, and getting faster consistently. Both at a language/computation level, and for things like web servers. ASP .NET Core Kestrel webserver has throughput only topped by a handful of Rust/C++ libs, and most recent preview included a new functional router API that increased throughout by +100,000rps.

- C# as a language is evolving rapidly and has already become a solid multi paradigm lang. Adopting FP functional features like pattern matching and lambdas. It has LINQ. It's actually pleasant to write now and doesn't always feel like verbose enterprise garbage. (I prefer modeling entities as classes/structs + using pure functions for working with them)

- The tooling and ecosystem of C# and .NET are rivaled only by the JVM. The developer experience and quality/depth of libraries available are fantastic.

There's more but that's off the top of my head.

Needless to say the last few months visiting C# and .NET land have changed my former opinion.


> Long story short, it's now possible to use C# and .NET to directly interop with C/C++. Function Pointers, structs and all.

Note that this has always been possible - good native interop has been one the design goals from day 1. But recent features have definitely made native interop much nicer.


> but what's so good about C# nowadays?

F# :)

Seriously though, I think regardless which flavor you use .NET Core is pretty good. You can work on whatever platform you like and deploy to any platform you like. There is usually at least one good library for the most common tasks (http, database access, cloud, big data) you might encounter while working as a software engineer.

> but Microsoft's software is known for being buggier than one would expect

I am not sure about this. Microsoft's software is used a lot more than anything else. They invested in software quality and FOSS a lot since the Ballmer era. I am generally pretty happy with the quality of MS software I use (.NET Core, VS Code, F#).


I think if you're not a Windows-centric developer it's a bit of a hard sell.

Having grown up with C, then C++ I find C# as the best compromise: expressive language, garbage collection, good performance, non-fussy syntax. When C# first showed up it was painful because for every other thing you had to call out to native Win32 libraries but nowadays I almost never find myself doing that.

Over the years the team added new language/runtime features at just about the right time: tasks, async, dynamic, reasonably tasteful collections.

For me Visual Studio Enterprise is a big part of it as well. I like plenty of open-source alternatives but honestly VS is where it's at.


Yeah, I've heard that Visual Studio's debugger is awesome and has no competitors.


VS' debugger allows you to manipulate code while debugging it, with some limitations e.g when you're writing COM code, but generally the craziest thing I did was putting breakpoint after SQL bad call, editing SQL string, at function exit adding call to itself with passing the same args, going into the same function and catching the same breakpoint while executing new SQL and then removing that function call and letting program continue.

it allows you to evaluate expressions at fly

it allows you to back in time (move e.g 2 LoC above)

it allows you to use the Immediate window to debug and evaluate expressions, execute statements, and print variable values. The Immediate window evaluates expressions by building and using the currently selected project.


I still haven’t tried it, but apparently rider is even better than VS. Especially for unity developers as it gives informations from the code as well as the Game asset files.


I used VS for something like 15 years, before switching to Rider few years back - Rider's debugger is now even better than VS's, IMO.

For example, I always found "edit and continue" really flakey in VS - it was really slow, sometimes using it resulted in a long hang or an outright crash, and quite often the IDE wouldn't even give me the option to use it. Rider is rock-solid by comparison - I'd say VS (with ReSharper) and Rider are roughly at feature parity, but Rider kicks VS's arse on stability and performance.

Another thing I'd add is that all of Microsoft's UserVoice-type feedback sites are an absolute joke - you might as well be piping your ideas into `/dev/null`. I feel like JetBrains actually listens much more to what developers are asking for.

Huge fan of Rider, and actually JetBrains the company too.


I'll explain it this way: I can build anything you can build in any other language. And I'll do it faster, easier, and with a more maintainable product. And with the latest releases, it'll also be one of the fastest, lightest, and most compatible applications too.

Everything from the fantastic IDE and tooling, to the massive and comprehensive standard library, to the wide range of outputs (CLIs, websites, APIs, mobile apps, games, native desktop apps), to the cutting-edge projects like Blazor (first component-based UI framework not in JS that can be run client or server-side) means you can build whatever you want without much overhead. Even language and framework features like LINQ are unmatched.

If you want a single word, I'd say it comes down to pure productivity.


The thing I mostly miss with the current .NET ecosystem is the capability of making desktop GUI applications easily on Linux.


What I love about C#:

- very active language development, modern functional features - very strong standard library. I used to take this for granted, but over the years I realised many other languages and are nowhere near where .NET is - exceptional IDE. VS has no competition


> VS has no competition

True. Rider comes close, but it's no VS


As a very happy convert to Rider, I'd beg to differ.

Interested to know what features or characteristics you feel are absent or lacking in Rider?


Handy and expressive language, power-full ecosystem (libs, community, tooling)

Especially tooling, people might like it or not, but I think MS has really strong people working on languages and combining compilers and tools, so you have things like editing code while debugging it (at fly), evaluating expressions at fly, IDEs that makes you use refactor often and make your life waay easier and those are only things that I notice the most

https://www.youtube.com/watch?v=bEfBfBQq7EE


> Please, help me correct my prejudices :)

We could start with the one that MS code is notably buggy :)

As far as I know most of the bread-and-butter consumer visible stuff is still mostly c++ (e.g. office suite, windows, etc.). I imagine there is a bunch of C# in Azure etc.

I could easily be wrong, been a while since I've spent much time with anyone working there. But these things have momentum and clean rewrites usually fail.


I've had bad experiences and reliability issues with some of their software. For example: OneDrive for Windows, Teams, Azure AD, Windows Bluetooth Stack, Azure Functions, Azure SQL Database.

All of those are mostly ok, but we encounter reliability issues on a more frequent basis than software from other vendors, like Amazon and Google.


FWIW I wouldn't hold them up as a beacon of good practices either, but I've found them about average for issues, perhaps a bit better than average for response & docs.


C# is a general language, not strictly tied to Microsoft (only dotnet was, but dotnet core fixed that generally).

C# is a heavily OO language with powerful semantics. If you like Java but hate the JVM, C# is your friend. C# has traditionally had much better developer aesthetics than Java but that gap has closed some.

Also worth noting the Java licensing has gone batshit insane in the last version or two.


OpenJdk Is GPLv2 with class path exception. I don't know how that is batshit insane.



It was literally open-sourced completely to the last bits even - that was the update grandparent likely references. But it is without doubt a positive update, so there must be some misunderstanding.


Usually the misundersting comes from Oracle hate, not understanding that without them Java would be stuck in version 6, and since version 10, it is no different than having Fedora and Red-Hat Enterprise.

The problem is that there are always those that rather go with CentOS.


Oracle has been a great steward. I just wish the community would move forward past version 8 sometime soon.


i think there's more people in the hate java, love the JVM camp.


Bitwarden is written in C# (https://github.com/bitwarden/server). If you want a project that impresses you, look at Ryujinx (https://github.com/Ryujinx/Ryujinx)


Also jellyfin, and I guess Emby which it was forked from

https://github.com/jellyfin/jellyfin


This kind of project is what could make me use C# instead of Go for my server needs

Microsoft is sitting on a gold mine and they don't know it!! yet!


I have a feeling that Microsoft is abundantly aware of the value proposition of the new .NET ecosystem.

C# has always been a good systems programming language. NET Core/5/6+ have just taken that to a new dimension with x-platform and better tooling.

The best thing about the MS stack is that it is built for the 8000lb gorilla projects (I.e. their own internal stuff). If you have a unicorn solution that has 2000 projects and requires 36 hours to build, visual studio, msbuild (dotnet build) are the things you want to be relying on to get you through the day.


Msbuild will definitely cope with that. Visual Studio, for all that it's a great IDE, gets creaky around 50 projects, I cannot imagine how long it takes to load 2000 of the things.


VS2015 was the last sturdy release. With VS2017 I had occasional hangs and crashes, but VS2019 either crashes or needs to be rebooted a couple times per day just to function. Intellicode is constantly breaking, test explorer only works reliability once a month, and it corrupts itself badly enough to need manual obj/ deletion at least once every few weeks. In their infinite wisdom, msbuild devs decided not to always clean the obj/ directory in the clean target by default. This is my experience on solutions with around a dozen projects, maybe 500k-1m loc across the solution. And it still barely understands how to use ram. Even if you let it see 64+gb, it will swap to disk.


visual studio became slow and laggy (interface) the day they ported their UI to C#, then it went downhill and i moved to sublime text, i still have to use VS, only for the debugger


Why would I use tooling that isn't open source?


I think if the author of it were here, he'd say that this is a proof-of-concept that he was working on to play around with NativeAOT and Crossgen 2 so that he could see what could be achieved with them.

Sometimes things get posted to HN as if they were "you should use this because it's the future" rather than "this is a cool thing I made to show what could be possible".

In the author's own words:

"I'm Michal, I live in Slovakia, and I work remotely at the .NET Runtime team at Microsoft.

In my spare time I work on C#-related side projects that I find fun but don't particularly overlap with my day job. You might know me from my greatest hits such as "Let's make C# run on Windows 3.11!", "How about a snake game in C# running on DOS?". I also write articles such as the one on how I built a fully self-contained game in C# in 8 kilobytes."


(Author here, I hang out on HN.)

Yup. There's really not much extra code in bflat compared to what's in the dotnet/runtimelab repo (in the NativeAOT branch). This just packages things differently so that one doesn't need the .NET SDK (plus Windows SDK if targeting Windows). The 100 MB bflat ZIP is all that's needed to target Windows or Linux.


I think if a compiler gets posted to HN as if it's being provided for general use, asking for its source code is reasonable.

The author is perfectly within their rights to keep it private, and we are perfectly within ours to call it out.


It's like Go but old!


To me, Go feels like the antiquated language.




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

Search: