Hacker News new | ask | show | jobs
by cm2187 1483 days ago
I think the language is great, if you can tolerate windows, it's a great way to write in the same language desktop applications, CLI and websites, and with wasm even web clients. It's the right mix of performance and high level language for my taste, and the tooling (visual studio) is fantastic. The integration with Windows makes a lot of things easy within a windows ecosystem. Also the self contained nature of the binaries makes deployment a lot easier than say python (everything is xcopy compatible with little dependencies on the client).

However in term of recent evolution, I feel that under Anders Helsberg there was a focus on simplicity. Then Anders moved on, and anarchy followed, with multiple frameworks, multiple attempts to combine them into one framework, and ultimately the greatest of all sins for a language: breaking backward compatibility (.net 4.8 vs 6). And it feels everything is getting complicated, command line first, async everywhere which makes everything multithreaded, prone to deadlocks and hard to debug.

The original c# had a great set of core libraries, however it has now fossilised. I think the owners of C# feel it is not their job to "update the batteries". So for instance their drawing library still doesn't support HEIC and might never do, they only added a json serialiser recently (yaml probably never). Instead you need to rely on a myriad of third party libraries with version conflicts, dozens of assemblies, and god knows if they will be available or maintained 10 years from now.

So while I am heavily invested in C# myself, probably too much to switch now, if I had to start from scratch now, I don't know that C# would be my first choice. But the need to rewrite everything for .net 6 might give me the opportunity to do that however I really don't have the time for that now.

3 comments

>I think the language is great, if you can tolerate windows

I do most of my C# development on Linux. Not sure why you need to tolerate Windows to enjoy C#.

Because you are missing out on the desktop UI capabilities of the language which is a great feature at least if you use it as a hobbyist like me.

And Visual Studio. To me the IDE matters as much as the syntax of the language. And when I was a beginner having an IDE that can interact with my code as I type it is a massive help to progressing.

VS Code, while not a fully-fledged IDE, is really good at suggesting code completions across platforms. As others have mentioned, Rider is also a wonderful fully cross-platform IDE (better than Visual Studio at some things).
Rider runs on Linux too
I worked on a (failed, explanation follows) project to trial port a large system from .NET Framework 4.6 or 4.8 to I think .NET Core 2.1 or 3.0. I was most annoyed at having to recreate project files, but it was quite straightforward and easy, even for us, where we had complications like numerous sub-projects, some generated code (luckily, I quickly found the correct arcane incantation embedded in some GitHub issue), etc. We also had to rewrite a C# API wrapper for a C library we used for reliable multicast, because our vendor had disappeared, and their wrapper was shipped as a Windows-only Framework-only DLL (and honestly, the code quality was relatively poor, with a lot of needless complexity in their wrapper). But we had already consciously chosen to only use sensible slices of that library’s functionality, so writing our own wrapper was quite trivial, even though I hadn’t used C#’s DllImport stuff before. It was easy to port the slice needed for most publishers first, before having to port the slice for receivers, etc.

All in all, I’d say the port for our large suite of server apps, with lots of different CPU/memory bound and network I/O bound apps, it was quite straightforward and easy.

What killed it in the end for us, was that our testing showed our CPU/memory bound apps ran 0.9x as fast on Linux .NET Core 3.0 vs. Windows .NET Framework 4.6/4.8 OR .NET Core 3.0, using near-identical hardware. The Linux port just wasn’t there yet, so we decided not to go through with any port to .NET Core for any part of our system, since Linux would have been the main benefit (we were using fancy network cards and stacks, and the Linux support for those was far more advanced and reliable compared to Windows, where multicast groups would spontaneously fail to be joined, etc.).

Another elephant in the room, is that GUI support on .NET Core was limited at the time, so we may not have been able to do a Big Bang for that reason also. We had a few WPF apps, and some Forms stuff, but I have no clue about what .NET Core support was/is for that stuff, as I rarely worked on GUI things (I would create a GUI as a necessary part of an experiment and hand it off to more experience people, or modify/simplify GUI logic as part of my evolution of our server stack, but that’s all).

So obviously YMMV and it seemingly does vary, but my experience on server apps that weren’t using lots of Windows/MS specific technologies (I’m not a fan of them generally), our porting was really quite easy. Still a failure though :-)

The performance improvements between .NET Core (any version) and (just) .NET 5+ have been pretty astounding. I've seen some incredible micro-benchmarks where the same code running in .NET 5+ hugely outperforms anything running in a version <= 4 (both .NET Core and the old .NET Framework). Factor in what you can do in memory-bound code by rewriting it to use .NET 5+ things like Span<T> and stackalloc there's no question that at this point you should be able to get much better performance out of .NET 5+. If performance was your bottleneck in .NET Core, the latest .NET versions (6 [LTS] or 7 [Preview]) may be worth checking out.

GUI stuff is also what happened in .NET 5+. WinForms and WPF were both added to .NET 5. There's some porting that needs to happen and not all old WinForms/WPF code will be happy on .NET 5+. The biggest remaining "missing piece" from a GUI perspective is that a lot of old WinForms/WPF code used WCF for service code. I think porting WCF to use simpler REST services is easy enough and there's lots of people doing that with gRPC services in .NET 5+ too. There's also the Open Source CoreWCF project that is trying to hit compatibility with the most used bindings in WCF on top of .NET 5+.

The relevant part were our model calculations and it was already heavily optimized (no allocations, etc.), so none of the new library stuff would help at all. We just found that Linux .NET Core underperformed compared to Windows .NET anything (Framework or Core). Maybe our methodology was wrong, but we had a few people look at it, made the comparison in several ways, and generally tried to be quite thorough. We always found Linux (only .NET Core) had ~0.9x the performance of Windows (any .NET) — and we were a mostly Linux shop, running C/C++ apps, so our Linux build was appropriately tuned. Given .NET Core was relatively new at the time, and Framework still had some legs, we didn’t dig down as far as looking at IR or JIT output, because we could afford to wait. After all, one of the draws was to reduce problems due to using our fancy network cards+stack in Windows, so there was no point in adding complexity from a new Linux .NET runtime, including complexity from having to troubleshoot performance.

I’ve been saying “we”, but I left that job a couple years ago so I won’t be trying any new .NET versions myself :-)

One of the issues I ran into when I looked at porting to .net core 3 was the crypto library. They didn't implement all .net framework classes, the ones related to public/private keys in particular. Perhaps they do now. I don't know how many edge cases I will find like that.

On the recreating project files, I don't think you can copy-paste winform code like that, you need to recreate it using the UI, which is a pain. Also they had this weird concept that an assembly had to be set to be a "winform" or "wpf" assembly, you couldn't simply reference system.windows.forms, which basically prevented you from creating a helper winform assembly, and you certainly couldn't create an assembly that referenced both winforms and wpf DLLs. They perhaps also fixed that since.

In any case, it's not a complete rewrite to migrate to .net 6, but it is far far from a simple lift and shift.

I’m not picking on you specifically, it sounds like you do a lot of desktop .NET development and there are legitimate complaints there.

However, “too invested to switch now” reminds me of .NET/C# developers that don’t embrace change and/or don’t swim in other waters.

Some folks with a traditional Microsoft/Windows/.NET Framework mindset have real trouble with these things:

>“Windows and Visual Studio”

Rider, Linux, Docker, bash terminals, and MacOS are all things that can improve your ability to solve problems with .NET. I’ve met dozens of people that refused to even try a different OS/IDE and fail to gain the benefits of those tools and the broadening effect they have on your perspective.

>”too many frameworks”

This complaint sometimes stems from an unwillingness to learn web/mobile frontend technologies. On the server-side, ASP.NET continues to simplify— you can write an API now in one file with a handful of lines of code. [1]

>“limited core libraries”

The first party support in .NET is already pretty comprehensive. Some folks have an aversion to using open source packages, but this is exactly how you get things like YAML parsing in most other languages. Microsoft’s move to open source has been awesome. You can literally interact & contribute with the team’s that make the framework.

>”command line first”

This sounds like a feature to me. This allows for automation and is easier to document without a series of screenshots. Having a common CLI allows a team to mix their preferences of IDEs/tools.

>”async everywhere which makes everything multithreaded, prone to deadlocks and hard to debug”

I disagree. async/await makes it easier to write readable code without deadlocks or many of the other pitfalls of multithreaded programming. It is not inherently multithreaded either [2].

Since it’s ‘everywhere’ and thus fundamental to writing C#, it’s my first interview screening question. A large number of candidates, with a lengthy .NET background fail to articulate any issues with calling “.Result” or “async void FunctionHere()”. IMO, you have to deliberately avoid understanding such a ubiquitous language feature.

[1] https://docs.microsoft.com/en-us/aspnet/core/fundamentals/mi... [2] https://blog.stephencleary.com/2013/11/there-is-no-thread.ht...

> However, “too invested to switch now” reminds me of .NET/C# developers that don’t embrace change and/or don’t swim in other waters.

Or I have other things to do and I don't want to have to relearn and rebuild everything for no obvious benefit. I have no fascination for the tool, I am keen on what I can do with the tool. Having to rewrite something I already did because someone decided to change the internal architecture of a core part of the framework is a waste of my time. The .net team used to understand that.

> This complaint sometimes stems from an unwillingness to learn web/mobile frontend technologies. On the server-side, ASP.NET continues to simplify— you can write an API now in one file with a handful of lines of code.

that may be but compare the amount of time it takes to drag and drop a button on a winform, double click on it and write your code vs doing the same thing web based. I also do websites, but the time invested to do a simple UI is an order of magnitude what it takes with a desktop app, so I need to have a really good reason to go web based for a home or internal project (and now I need to deal with a server with certificates, etc). And there are many applications where it is simply not possible. Interacting with files, or visualising non h264/aac videos, selenium, etc.

> This sounds like a feature to me

I am not saying it is not intended, I am saying it is more complicated.

> It is not inherently multithreaded either

Yes it is. You need to constantly think whether you are going to come back on the same thread or not. Something that works fine on a console application or within an exceldna formula will deadlock on a asp.net or wpf application. And it breaks the call stack when you get an exception, making it harder to debug. I think I understand this feature reasonably well, thank you.

And not just multithreaded, asynchronous also. That means if a user clicks a button and that button has async code, the user can do more interactions with the UI while the original method is running. Now you need to handle many more UI states than you had without async.