Why Tracebit is written in C#
308 comments
·January 31, 2025unsignedint
mattgreenrocks
This is going to sound really unfair, but compared to some of the more hip languages, the .NET/JVM ecosystems feel a bit more like they have adults at the helm who at least try to maintain backward compat. They’re also stodgy as hell sometimes, but I’ll take that. There’s a real difference in culture that manifests in both what is made and what is held up as good engineering. And that has an effect of raising the bar on what is acceptable from an ecosystem POV.
Yes, it’s possible you’ll have to deal with Enterprise-y code sometimes. But, it’s usually your team’s choice as to what is written. Also, people don’t seem to complain quite as much about it when they encounter it at a FAANG elsewhere that tries to do “good” engineering, but that’s another discussion. :)
CharlieDigital
> They’re also stodgy as hell sometimes, but I’ll take that.
Can't speak for Java, but C# has been evolving very rapidly and for the better with each iteration.I feel like the C# team really focuses on DX when evaluating language features.
Best place to get a feel for how rapidly the language evolves for the better is the version release docs for C#:
C# 13: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/cs...
C# 12: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/cs...
C# 11: https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/cs...
etc.
Compared to JS, Go, Java, etc. I feel like C# evolves significantly faster and the team is faster to validate, implement, and deliver improvements to the language.
I think this is also why some folks who tried C# say 5-6 years ago have no idea how fast the language has evolved for the better.
fsloth
"This is going to sound really unfair, "
That's not unfair at all, I think it's a fair assessment. Industrial tools should have adults at the helm. People who care about longevity and robustness foremost. About delivering quality and stability where the main value points of a language are.
unsignedint
Yes, they place a strong emphasis on backward compatibility, particularly with language features. This allows new C# language features to be gradually introduced into a codebase without disruption, which is especially valuable in enterprise environments. It may feel stodgy, as you say, but they continue to add interesting features with each C# release, striking a good balance between stability and innovation.
fortran77
JVM is a giant mess! I'm surprised you considered both together.
mattgreenrocks
Not sure why you’re downvoted. Happy to hear your experiences good and bad with it.
My quick take: Kotlin is a joy to write in, Jetbrains tooling is pretty good (though a bit dicey lately), build systems seem a bit eh, and the whole ecosystem is a bit too locked on spring boot. I use Quarkus, which has been pretty good, but it is much smaller in terms of user base.
Kwpolska
Upgrades between modern .NET (Core) versions are simple and painless. It’s just a single-character change in the .csproj file, plus maybe upgrading some dependencies (but old versions will usually work).
Upgrading from the classic .NET Framework to the modern .NET is usually a long process. Simple console apps, desktop apps, and libraries might be doable with an automated csproj upgrade. But Web apps require a rewrite from scratch, because the old ASP.NET is incompatible with the modern ASP.NET Core.
pipes
This hasn't been the case for me at all, the jumps between lts releases have burnt a lot of my time figuring out how to fix broken things. Though c# is definitely my favourite language to work in :)
jbluepolarbear
What difficulties did you experience? I’ve upgraded many projects from ancient C# v2 and more modern versions. There are always some things that need to be addressed, but as long as you look at the changes from the one version to the next it’s easy enough to figure out what needs to be changed. Most modern IDEs will point out the issues in an upgrade report.
Clubber
>It’s just a single-character change in the .csproj file
When .NET 10 comes out, it will be 2 characters, double the work of the previous process. Unacceptable!
/s
ThunderSizzle
I hope they move to just using the current year as the version soon, probably after 10.
sandreas
What I really like is the fact that you can basically build anything in this language. From command line tools over Apps or small GUIs up to full fledged Server Backends or Webservices, even WASM... everything is possible.
The NativeAOT approach is also very interesting making it possible to build native binaries similar in size and performance to languages like Rust and Go (not quite actually, but close).
It's also possible to build "single binary" tools by using <PublishSingleFile> which comes in handy when building small helper tools for the command line.
billfruit
The same is even better with Java.
It's common to find Java binaries build 20 Years+ to run on present day systems without issue.
porcoda
Yup! I recently took a pretty substantial project I wrote in 2006 in Java that was sitting in a tar file, unpacked it, and it ran just fine with a current JVM. Even better, I was able to compile it again with no problems: again, with a modern JDK. I wish I could say the same for years of projects written in Rust and Haskell: the Haskell ones are almost all bit rotten since I haven’t kept them up to date with GHC, and Rust is similar. Those two are even worse since with Java I had a rich standard library, so I didn’t have any 3rd party dependencies in my 19 year old project. The Haskell and Rust ones rely on Hackage and crates, and keeping things working for that long would require me to do bonus work beyond my actual project code. I’ve had similar but less painful problems in Python land: the library APIs are mostly stable: the biggest headache there are projects that predate python3 so there’s some work to bring them up to date. That’s at least a one time investment.
Java: no bonus work induced by third parties to keep projects alive, keeps working for a long time. Would recommend.
tialaramex
> I wish I could say the same for years of projects written in Rust and Haskell
Back in 2021 I ported a small C program I wrote into Rust as part of learning the language. Since I was inexperienced even though it's small and Unix specific I added about two dozen dependencies including transitively a Windows API dependency via somebody's terminal lib.
So, that's a 2018 Edition Rust program, untouched since November 2021.
The binary of course still runs just the same as ever, I've used it a few times over the intervening years - but we'll take that as read. Lets go into the source code and build it again today, how much work will it be to get Rust source code working years later with a brand new Rust toolchain and different OS?
It just works. Not like "Well, I had to run some updates and modernisations" it just works.
tome
> the Haskell ones are almost all bit rotten since I haven’t kept them up to date with GHC
FWIW, over the last couple of years the stability story has got hugely better, thanks largely to the efforts of the Haskell Foundation Stability Working Group.
You can see the breakage inventories that I've produced for the last few GHC releases, and see that the amount of breaking changes is decreasing rapidly:
KronisLV
> Yup! I recently took a pretty substantial project I wrote in 2006 in Java that was sitting in a tar file, unpacked it, and it ran just fine with a current JVM. Even better, I was able to compile it again with no problems: again, with a modern JDK.
I've seen plenty of Java projects that don't work on anything more recent than JDK in the enterprise space (typically large Spring systems, not even Spring Boot, also DB drivers and pooling solutions seem to be quite brittle in that regard), though I will say more or less the same about old .NET codebases (before Core was a thing), old PHP, Node.js and so on.
Most of the time, it comes down to complex dependencies.
omcnoe
Stackage is mandatory for a “stable” Haskell env, even for simple/toy projects. It means you get predictable versions for GCH + hackage libs until you explicitly choose to upgrade.
merb
this is definitly not true anymore, when the java libs used jaxb/xml/javaee stuff. most often because of java 9. its possible to make them running but its definitly not without issues. I did run so many 10 years old java binaries it was NEVER without issues.
mgh95
From what I gather, the only time this occurred was very early in the C#/.NET ecosystem (.NET2) when generics were added in November 2005. So it should be at 20 years this year.
Both languages are very impressive and benefit from the competition.
pjmlp
There were more breaking milestones, .NET to WinRT 8, WinRT 8 to UAP 8.1, UAP to UWP, UWP to WinUI 3/WinAppSDK,.NET Framework to .NET Core, Silverlight, XNA, Managed DirectX.
All of those are also part of .NET ecosystem.
Agree with the competition remark, hence why my toolbox has been .NET, Java, JavaScript ecosystems on the first drawer for decades now.
cyberax
Early C# often depended on libraries that were MS-specific, partially native code, and are often no longer even available.
This changed around 2014-ish, as a result C# has been really stable for a decade.
sixothree
The number of times I’ve had to install an older version of Java just to compile some code is not even remotely funny to me. I really hate this idea that you can have code that just won’t compile if you are using a modern environment.
whoknowsidont
>With .NET, this issue is much less pronounced.
This is because Windows comes with some form of .NET, but also other programs end up needing to install multiple versions of the .NET runtime. Eventually, you just have them on your machine. It's the equivalent to installing every version of Python and just letting the problem sort itself out.
It's not different than other tech-stacks, you're just eating the costs up front instead of running into them in a more obvious manner.
.NET (in its entirety) has lots of breaking changes that won't work from one version to another. More recently MS has been better about documenting these, especially as .NET's footprint increases inside outside of the control of MS (non-Windows environments): https://learn.microsoft.com/en-us/dotnet/core/compatibility/...
>In fact, PowerShell itself is another reason I appreciate .NET it shares many concepts
PowerShell is built on .NET (in whatever form .NET Framework and .NET/core) lol. It doesn't "share" anything, it _IS_ shell for .NET.
rqtwteye
I was excited about PowerShell at first but after doing a mid size project it, I don't like it anymore. It's such an odd language with too many quirks once you get serious. I think they would have been better off using C# syntax.
hobs
The syntax is barely the problem, the weird console rendering of objects behavior, the mixed object/text representation (since not everything buys into the objects), the breaking changes in the cross platform posh, the poor library support and requiring to load the world on importing modules... there's a lot of stuff powershell got wrong enough to avoid anything with it, and I have done plenty of serious things with it :)
patmorgan23
Because PowerShell is a shell interface/scripting language. That's like complaining it was difficult to build a project using bash or CMD.
It's great to system administration, having named attributes + pipelining is awesome compared to bash/CMD
null
zigzag312
A few years ago an option to make self-contained builds was introduced, meaning you don't need any .NET runtime on your machine to run the self-contained app.
unsignedint
Yes, but in the case of Python, I feel it's a bit more nuanced. Simply having Python installed isn't enough—you also have to manage virtual environments (venv, Poetry, or whatever is popular at the moment). Personally, I find this to be more of an ongoing maintenance burden.
I do acknowledge that .NET has its share of breaking changes from time to time, but in my experience, the friction is significantly lower compared to other environments I’ve worked with.
> PowerShell is built on .NET (in whatever form .NET Framework and .NET/core) lol. It doesn't "share" anything, it _IS_ shell for .NET.
I never said it wasn’t! I was simply speaking from the perspective of the frontend experience. While PowerShell is built on .NET, my point was about how its functionality and design make it feel familiar to those already accustomed to .NET development.
whoknowsidont
>my point was about how its functionality and design make it feel familiar to those already accustomed to .NET development.
Because it's literally a "shell" into the .NET runtime/framework. PowerShell _extensively_ uses reflection capabilities.
My point was they're not sharing some design philosophy or converging, PowerShell is just exposing .NET functionality directly and in an interactive manner. You in fact, can write a pretty similar tool with a few lines of C# that makes use of dynamic compilation and reflection.
Otherwise, PowerShell shares nothing (and I mean nothing) with other .NET languages (C#, F#, etc). It's history and design choices come from things like KornShell and Perl.
Where do you think all those $variables and "-ne" operators came from?
scarface_74
> One thing I appreciate about C# and .NET is how well they resist codebase rot.
During the time I was working with .net from 2005-2020, I saw the transition from Webforms to ASP.NET MVC to the MVC/WebAPI split. I also saw the transition from Linq2SQL to Entity Framework.
There was also the weird time when you could run ASP.Net Core and EF Core on top of .Net Framework.
Then the entire .Net Framework to .Net Core was a major upheaval.
oaiey
It was necessary and worth it.
amelius
Microsoft is king of backward compatibility.
brainzap
to only downside, If you support everything, everything will be used. Deprecating aggressive hurts shortterm but pays off long term.
LeFantome
C# is one of my favourite languages and .NET is an awesome stack top to bottom. The interoperability between F# (a fantastic functional) language and C# is a real bonus that was just touched on in this article. Writing a compiler for .NET is easy and fun as you can target CIL (Common Intermediate Language) either as binary or text (.NET assembly basically). Something that builds in .NET today will probably run 20 years from now but faster.
Another benefit that is really stands out once you start using it is that you can write anything in it. It integrates to C well and you can get absolute control over the bits in memory and on disk if you want. You can avoid the garbage collector most entirely where you think you need to. You can also operate at a high level of abstraction. It has, if anything, way too many web and GUI frameworks (even just from Microsoft).
And that last part is the rub…
The downside of C# is that it is both old and rapidly evolving. That means multiple competing frameworks. That means that the complexity of the language keeps increasing. It is not quite C++ (and WAY better designed) but it has the same problem. The number of features and the breadth of syntax is non-trivial. There is also a bit of “magic” that has crept in that allows you to skip boiler-plate with the side-effect of basically have behaviour you cannot see in the code. All this is optional.
If you write everything green field with some coding standards, it is no problem. But if you want to read other people’s code, there is a fair bit of language to learn.
Like English, C# is incredibly useful and can be used anywhere. Like English, it is super easy to pick up and use. Like English, it feels like you can use it your whole life and still not know it all.
ycombinatrix
>Like English, it is super easy to pick up and use.
Um. Have you tried learning English? This is definitely not the case.
ThinkBeat
One of the problems with C# is the constant expansion of the language. Microsoft wants it to be everything for everybody, instead of sharpening it in one direction.
If you have a lot of experience in C# 2.0, later code may be quite incomprehensible. (Yes this goes for other versions vs the latest version as well)
Whereas I can pick up a C program today and have a decent understanding of what it is doing.
Then the codebase becomes legacy a lot faster than most other environments. It will compile and keep it, but programmers want to stick new features into the codebase.
F# to the limited extent I have followed it seems more stable in terms of added features. C# has certainly adopted a lot of features from F".
My second big gripe with Net is EF ORM.
If the developers using it are not reasonably aware of how a relational database works, you can get truly horrific code. A dev team at a client I was at, managed to spike the SQL Server instance to damn near 100% for at least 30 mins.
When someone discovered the what and where was causing it.
A pure SQL statement replicating what needed to be done ran in seconds.
magicalhippo
> If you have a lot of experience in C# 2.0, later code may be quite incomprehensible.
I did a lot of programming in .Net 1.1 and quit just after 2.0 was released. I've then spent all my time in other programming languages. Past year at work we've been starting our transition to .Net. I must say I found exactly the opposite.
All the things I knew I could still do, and I found the new stuff quite readable. Sure I had to do a couple of searches to read up on some of the changes, but overall I've been productive in .Net 8.0 from the moment we started. I have had no issue reading library code, as one does to figure out what's really going on.
Also, Visual Studio guided me to rewrite my outdated code in better form, which also helped to understand the changes.
This is entirely unlike C++ which I also used a lot before and quit just shy of C++11 getting released. These days when I read some modern C++ code I frequently have absolutely no idea of what's going on.
As for EF I don't know, as the database we still have to support doesn't support it so haven't had a chance to use it yet. If we do, we will be writing our own SELECT statements for anything beyond a trivial primary key lookup though.
YMMV.
Hawxy
Modern EF Core can generate SQL very close to handwritten and will aggressively warn you if you do something dumb. I wouldn't worry about it.
magicalhippo
Good to know, though we have mostly either trivial (ie by indexed key) or complex queries, with very few "medium complexity" queries.
For the complex ones we like to have full control as it almost always turns into a major ops issue if the queries are not performing well.
Though perhaps if we can catch changes of the generated queries in our test suite we could let EF generate them. Trust but verify kinda deal.
ThinkBeat
My example was 9 months old. At least in this instance EF did not warn, and caused great problems.
kkukshtel
C# 2.0 was twenty years ago - in 20 years any language that is actively maintained is going change, especially as people adopt new syntactic sugar to write more concise code. However the .net team rarely ever breaks backwards compat with new features, and the only thing in recent memory was them adding a new keyword for implicit backing property fields (and I also felt their solve was elegant).
C has this same “problem” but I expect it’s less prevalent because most people still write in C99 and ignore newer C features (similar to C++). https://floooh.github.io/2019/09/27/modern-c-for-cpp-peeps.h...
I think because the toolchain is unified, people tend to adopt newer C# features faster than other languages. You aren’t waiting on your permutation of msvc/clang/gcc to update, so when a new version releases, people update and start using new stuff. That said you can also write C# still like it’s 2005, but you’d be wasting time.
C# (to steal Jon Skeet’s language) has developed in the direction of removing “ceremony” in writing code. What in C# 2 would have taken like 20 lines to create a class in a CLI program and print a value can now be done in like 2 lines without sacrificing readability, and if anything is easier to read because you’re only looking at load-bearing statements instead of lots of flaff to scaffold simple behavior.
qayxc
I 100% agree with the first point, but the second one isn't C#/.NET related at all.
ORMs pose the same problem regardless of the language/framework or implementation. I've seen the same issues with Java's hibernate, too, no difference there.
littlecranky67
Except that EF Core is way more modern, thin and with sane defaults (more like Dapper.NET Micro ORM) than traditional EF - which is a fat, untamable beast just as Hibernate (and NHibernate was). Plus, no one forces you to use ORMs. Just use plain SQL as with any other language if that suits your needs.
PeterStuer
.NET 's initial appeal was that it felt like Java before the architecture astronauts and the bloat with a saner GUI approach to boot. These days they not only caught up but are trying to surpass in those areas.
It seems to be the doomcycle of life in development stacks. Fresh system cuts through the accumulated cruft of the old, only to gather more and more niche cruft until it collapses on a beach of arcanary while the next wave of simplicity rises behind it.
zeroc8
Java has been doing great recently and I feel there is a bit of a renaissance going on. There is a very mature leadership at the helm and it shows. With .NET, it seems that they've added features too quickly without giving it enough thought up front. If you are a small team or working on a short lived project, this might not matter. But for long lived projects by large teams, I'd rather take the more conservative approach.
jeroenhd
Java has been playing catch-up for a while after the ecosystem stagnated on Java 8. The language seems to be very willing to incorporate new changes, but most interesting improvements seem to be stuck behind "nth preview" developments (basically useless), or the release was as badly thought through as any C# feature.
For instance, Loom took ages to make it into Java itself, finally reaching an LTS version in Java 21, but it took until Java 24 for Loom to be able to deal well with any code hsi g synchronized {} blocks. They also went back on their previous advice ("change synchronized blocks to reentrant locks to fix compatibility") which must be fun news for the projects that did follow their earlier advice.
And while introducing modules and breaking the compile for any old Java project seems to have gone through without much trouble (throwing compiler warnings everyone ignores for several releases before breaking code, of course), the language seems to dread minor backwards incompatibilities when it comes to language level improvements like nullable types, introducing a tri-state nullability definition while also refusing to implement some stricter null checking to ensure the language feature is entirely opt-in.
Java feels like the backend is picking up features as fast as Javascript or Rust or C#, but the frontend is managed like C. A weird mix between "change is scary" and "stagnation is decline". It's the language at the forefront of high-performance dynamic programming while also having had an unimplemented "const" keyword for 25 years.
pjmlp
The architecture astronauts feel just like at home in .NET as well.
I have been part of both ecosystem for their whole lifetime.
doorhammer
C# is one of my favorite languages and I generally think the features they add are high quality and provide a lot of real value, but I also agree that the flip side of that coin is a pretty large language. I think you have to be pretty good at establishing and maintaining style standards that are a bit picky about which features you're going to use, which is a non-trivial thing to do socially in a lot of orgs.
Obviously in a greenfield startup like the article (I'm assuming) it's maybe a bit less of an issue--at least to start? Definitely a challenge, though, especially compared to something like Go or C.
Imo ORMs are useful as a way of making common actions easy and quick but that thinking they shield you from knowing what they're doing and how SQL works can quickly cause a ton of problems.
There are a lot of EF queries that don't even need to into raw SQL to radically improve (though 100% that's the case often enough). Some `n+1`'s and `ToList`'ing million record queries into memory when you need the top 5 being examples that come to mind.
EVa5I7bHFq9mnYK
But you can still write C# 1.0 compatible code and it will run ok. Just don't look at the new features. They added quite a bit of low-level performance related features recently, like span, ref, template math, readonly struct, vectors etc, which are quite useful for the performance minded, but can be safely ignored by the CRUD crowd.
arnonejoe
Agreed. Early on before .Net Core the language features were stable. The update to the 3.5 Framework around 2007 was a big deal at the time. Now it seems that new language features are cranked out at a much greater frequency with .Net Core. That said, C# when combined with the JetBrains Rider IDE offers the best developer experience over any other language/IDE combination I’ve worked with.
andix
You can set an old language version for a modern C# project. The compiler will behave exactly like 10 years ago, but it outputs a modern assembly.
If you think this is the way to go in your organization, just do that.
But I seriously don't get why it's so impossible to just read the changelog every year. Takes literally 2 hours per year. Most of the changes are quite self-explaining anyway.
danielodievich
I went skiing at Big Sky with bunch of Microsofties as part of Microsoft ski club back in 1999. One of them was a pretty big guy who on the first day of skiing took a bad tumble and threw out his knee. He had to stay at the chalet for most of the rest of the trip, missing out on some glorious snow. I remember asking him what he did while recuperating and he showed me what became .NET. He said it was going to be awesome and transformational, with many other nice adjectives. I didn't really get that from his demo, it was pretty rough, but yeah, he was right. I've been Csharping almost every workday since it came out as 1.0 and its an excellent framework, especially these days where it runs everywhere.
PeterStuer
"Tracebit is a B2B SaaS Security Product. If you did a straw poll of Engineers - especially readers of a certain orange website - about the ‘best’ language for such a system, I think the common responses would include Python, TypeScript, Golang, Rust, something JVM-y, maybe Elixir"
I guess everyone likes to be the underdog, but thruth is the B2B space is dominated by the duopoly of Java and .Net and shows no signs of changing.
The author is imho cosplaying as a contrarian while being solidly mainstream.
miki123211
I think C# has the highest ratio of (happy) programmers to internet discussions, at least among mainstream languages. This makes it look a lot less popular and cool for people outside the ecosystem.
I think that it's also much more common with companies that aren't primarily tech-focused, as those companies usually have cosy relationships with Microsoft. Pure tech companies, startups and FAANGs don't seem to use it much.
This also ties into geography. In the US, far more people work for startups, FAANGs and pure tech companies than in Europe, where traditional businesses and "software houses" are far more prevalent, which means there's far more C# there.
neonsunset
Which is a shame, because C# is usually better at the problems many startups try to make Go work at. It is a significantly stronger offering if you treat it as a middle ground between C++ and Rust family and Go/Java family.
It is the cool and modern language in today's landscape. But it is popular among the companies which use it the opposite way. Now, we shouldn't complain too much. Because this is what made .NET survive in the first place. But I wish more people looked at projects like Garnet, Ryujinx, various greenfield HPC and highload libraries in the ecosystem over yet another CRUD template. Business domain modeling is much better done in F# anyway!
rednafi
I can understand advocating for C# over the mess that is JavaScript, but with Go, it’s a different story.
Startups choose Go because no one I know is excited about working with GoF-style OO code these days. It’s easier to hire for and faster than C# for most workloads.
Yes, you can write C# in a data-oriented way, but no one does. So diving into an existing codebase means dealing with OO encumbrances, and not everyone wants that.
The compilation time is fast, and so is the startup time. Cross-platform compilation with a single command and a single binary makes life easier. On top of that, most infra tooling—Grafana, Prometheus, Kubernetes, Terraform—is written in Go, so choosing Go for the backend comes with a ton of advantages over C#. I can personally attest that this is exactly why Uber and now DoorDash have chosen Go over the alternatives.
rednafi
The author is most likely too young to have experienced this trend and has now rediscovered the joy of stability. Choosing Java, C#, or even Go offers a huge advantage in terms of stability, which takes years of experience to truly appreciate.
I’m loving the fact that the industry is getting tired of Node in the backend and the tech debt it incurs after a few years. Rediscovering old values and getting excited about them is perfectly okay. Nobody remembers all of history—reinvention is part of the process.
mattgreenrocks
Yep. You’ll wake up one day and realize the tech itself is not the interesting part — it was understanding and solving problems for people.
Thus, anything that gets in the way of that is not worth it.
whoknowsidont
[flagged]
neonsunset
You still posting? Impressive.
One thing I don't understand however is a complaint about getting higher quality comments than the ones you respond with. Hard data? Who cares about it, we're posting opinion pieces and vibes!
whoknowsidont
What do you mean by "still" posting? Are you monitoring my account and following me around?
noveltyaccount
As the author points out, Batteries Included is a big reason I choose C# over and over again. Every time I have to go to NPM or Crates.io and look over five or more packages to solve some seemingly basic problem I get exhausted and frustrated that I'm not actually solving the problem I need to. C# has so much built in, and while there are third party options, the Microsoft way is almost always good enough.
t_tsonev
Recently I've got bitten by the comically poor cross-platform cryptography support in .NET
Just look at https://learn.microsoft.com/en-us/dotnet/standard/security/c... and https://learn.microsoft.com/en-us/dotnet/framework/network-p... for a sneak peek into this madness.
novaleaf
FYI, You are comparing the modern version of DotNet (the first link) with the old legacy version (the second link).
The modern version of DotNet, "Net Core" is effectively a reboot of DotNet, with a very cross platform focus and redesigned API's based on decades of experience.
LeFantome
The impressive thing between .NET Framework (original .NET) and .NET now (rebooted as .NET Core but now dropped the “Core”) in that they largely foxed the API while leaving almost all of it intact.
Library code you wrote in C# 10 years before .NET Core will often just compile and run. Even more than code the resides developer learning. The plumbing between ASP.NET MVC (old) and ASP.NET Core (new) was completely and radically different. Yet writing an application in it was very much the same.
Nuzzerino
The first link appears to be for .NET Standard, which has a common API compatible with both Framework and Core.
Though it might be worth checking Github to find example usages of the APIs. Maybe there's even some libraries that improve the developer experience with cryptography.
neonsunset
These limitations come from cryptographic implementations provided by specific platforms, not from .NET. Can you list specific algorithms you need that are not supported?
The second article uses the wrong link too (it's for Framework, not for .NET).
jeroenhd
As someone with no horse in this race, I must say that I'm a little disappointed in the way Linux "compatibility" deals with platform differences. Most parts of the crypto API seem to be marked as "works on Linux if/except when" which seems strange given that porting to macOS didn't seem to impose such restrictions. In some cases, the inner workings of the underlying library works differently and you get an exception when using certain functionality on Linux at all.
I though Microsoft did better porting dotnet to Linux. I knew they don't care about Linux GUI, but I hoped they'd at least do system libraries better.
littlecranky67
You should be good when using .NET 9 and openssl 3.0+?
sophiacamille
I have tried quite a few languages over the years. C# is my favourite. I don't really know why, it just feels like a cosy, warm jumper.
bartwr
I share the sentiment. I haven’t used it in a while (at work use different languages and in the last few years my personal coding is only Python script/Jupyter notebook bite-sized), but anytime I hop into it, it immediately "clicks" and gives a comfortable feeling, despite changing over years. A perfect language for medium sized relatively clean and mature personal or small team projects.
Frictionless, pleasant, not thinking too much how to express things (and still managing to write them reasonably idiomatic), tends to support clean encapsulated code, quite rich environment/libraries, great tools (debuggers, profilers), safe, relatively fast, not many foot guns, zero build setup, on small project zero build times, trivial to create good functional simple UI, can get fancy dynamic with reflection when I need "magic".
Basically not many pain points that would make me rage quit and almost everything I'd want is simple to achieve.
Akronymus
C# is my second favourite language, despite it being OOP first. My personal fav is F#.
taberiand
Each new C# release seems to borrow yet another F# feature, to its benefit. I prefer F# too, but at least I can convince the team to use C# - F# seems to be a bit too intimidating (in its awesomeness, I assume) for most devs to learn.
alkonaut
Same. I think it’s because it’s easy to read and write, and its worst design warts are at least not ridiculous like they are in say JS or Go, where there are massive cons to weigh against the pros. C# just feels like it’s pretty decent across the board instead.
bitwize
There's no programming-language cozy like Lisp cozy, but I can see myself working quite happily in C#.
halfcat
C# is solid. It’s not necessarily the best at anything (is it?), but its floor is like a 3 out of 4 across the board.
I remember making a big spreadsheet of languages and a bunch of potential areas of use. Building desktop apps, mobile apps, games, concurrency, performance, cloud native, web apps, data pipelines, and machine learning. C# is 3 out of 4 on all of those, except maybe 4/4 on games with Unity, and being cloud native with Azure, C# gives you a bunch of stuff automatically especially around observability.
Atotalnoob
C# has changed a ton in the last few years, it’s definitely 4/4 for me…
CharlieDigital
It's getting closer and closer to TypeScript.
yodon
You presumably are aware that C# and TypeScript share the same original language designer
Atotalnoob
They were made by the same dude, so it makes sense they are similar.
pier25
Probably the other way around...
caspper69
I am a huge C# advocate, and with the AOT stuff since .NET 7, they are really working overtime to add features for safe low-level operations.
Some of the niceties over the last several versions include immutable record types, stack allocated structs (ref structs), lambdas (and a host of enhancements thereof since), async/await (of course), generic math ops, platform intrinsics, pattern matching, AOT, nullable types, robust generics, reflection, dynamic types, etc. The big thing I expect next is algebraic data types.
The language has really grown by leaps and bounds, but it doesn't ever feel overwhelming, and it has really kept its verbosity to a minimum without turning into a soup of hieroglyphics.
That being said, I have found the Android/iOS solutions to be underwhelming. I understand the iOS side a bit, but I thought Android would be better. That's not to say you can't make great applications using C# on these platforms, just that it requires more effort.
I'm also not a huge fan of ASP.Net. I've never really cared for it, and I think that stems from a project I had early in my career duct-taping together another developer's classic ASP applicat^HHH monstrosity and mucking about with IIS and FoxPro (!!). I know it's not classic ASP, but once bitten, lol. I will say that it is modern and performant, but very rigid. I'd defer to others' opinions here because I have mostly avoided it.
But in general, the tooling is great, and I don't encounter much that ties you to a Windows box anymore. I know there are some differences in platform support, but most of the rough edges were handled in the early days of .NET Core 2 & 3. Now that we're way past that (the "traditional" .NET merged with .NET Core in a combined version 5 release). Now that it's on version 9, the language features and low-level hits keep coming. I can, today, write code that is 99% of what you can get from C++ (and in some edge cases can exceed it), compiled to native code, that will run on Windows & Linux (x64 & arm64), BSD & MacOS without too much trouble.
And as a fellow HNer pointed out the other day on an unrelated thread, the native interop is painless. You can load .dll, .so, .dylib files with ease. No frankenstein FFI (ala Go or Java).
The language is safe. GC can be avoided (or controlled), and it offers raw pointers, manual memory manipulation with spans, and more low-level features through the unsafe subset of functions.
I know people like to say this started as a rip-off of Java, and there is some truth to that, but I have too much respect for Anders to believe he set out to rip off Java part and parcel. There was a method to his madness, and from my perspective, C# has always been a step ahead in programmer ergonomics (but definitely not performance). Maybe that's due to the sheer intertia of the Java ecosystem, or to Sun and then Oracle being more conservative, I don't know. Hell, it probably had more to do with Microsoft's reputation.
I value programmer ergonomics and tooling, almost above all else, and I am a happy camper. You can write C# from several different angles as you see fit, and in most cases it checks all the boxes for a large subset of projects.
neonsunset
> I'm also not a huge fan of ASP.Net. I've never really cared for it, and I think that stems from a project I had early in my career duct-taping together another developer's classic ASP applicat^HHH monstrosity and mucking about with IIS and FoxPro (!!). I know it's not classic ASP, but once bitten, lol. I will say that it is modern and performant, but very rigid. I'd defer to others' opinions here because I have mostly avoided it.
Indeed, it's a completely different product nowadays.
Take a look at this! https://learn.microsoft.com/en-us/aspnet/core/fundamentals/m...
orthoxerox
Microsoft sucks at naming. They have reinvented their web stack several times, but have stuck with the ASP (.Net) moniker.
There's ASP, ASP .Net WebForms, ASP .Net MVC, ASP .Net WebApi, ASP .Net Razor Pages, ASP .Net Minimal API, ASP .Net Blazor (several forms of it, too). Some of them suck, some of them are very nice, but that's incredibly confusing for people not familiar with the stack and job seekers trying to determine how much they will hate the new job.
It's like React being called jQuery RX, Vue being called jQuery RX 2 and Svelte being called jQuery SX.
miki123211
> That being said, I have found the Android/iOS solutions to be underwhelming. I understand the iOS side a bit, but I thought Android would be better.
And Mac OS.
With the discontinuation of VS Code for Mac, I'm pretty concerned whether Microsoft is going to keep supporting those platforms.
I've only looked at .NET briefly, but it seems that they're not even adding new Mac APIs to the C# bindings any more, and most of the documentation mentions old Mac OS releases like Catalina.
I don't think they'll ever drop Mac support completely, as plenty of people develop ASP.NET applications on their Macbooks, but I'm very hesitant to use .NET for desktop applications where native integration is key. Especially now, when Microsoft seems to be going all-in on Catalyst.
They don't seem to care much about Xamarin either, favoring other technologies like React Native.
moron4hire
> With the discontinuation of VS Code for Mac
Wait, what? Surely you mean the version of Xamarin Studio that MS bought and called Visual Studio for Mac. I just used VS Code on a Mac yesterday.
Xamarin Studio was garbage. While I will admit it is not easy to get VS Code to play nicely with .NET (an irony that is not lost on me), it still remains possible to create a not-buggy, fully featured .NET development experience in VS Code. Neither of those qualifiers were possible in Xamarin Studio.
andhuman
I’ve worked with ASP.net many years and it mostly gets out of your way. I feel very productive with it.
vips7L
Java the language is conservative by design. They always are the last mover for language changes on purpose. They feel that it allows them to make better decisions and they don’t have to adopt bad ideas until other languages try them out.
ngrilly
I recently inherited a C# code base at work. I agree that C# is a powerful, productive, and mature language, but as someone who has been programming mainly in Go, Python, and a bit of Zig over the past few years, there are a few things that feel like a regression in C#:
- The absence of free-floating functions (everything is an object, and I must use static methods on static classes).
- When “using” a namespace, the convention is to make all the symbols in the “used” namespace available directly in the current namespace. That makes harder to know where symbols are coming from when reading code. And to avoid name collisions, people tend to use longer names. The convention in Go or Rust is to prefix most symbols with the package they are coming from. But perhaps I’m missing something and need to read/write more C#.
- The syntax for doc comments with tags such as <summary> is super verbose. I don’t see the point. Docs are working great without these tags in other languages. Reminds me of my J2EE days.
- I really prefer the name before type syntax (used in all new languages such as Go, TypeScript, Go, Swift, Kotlin, Zig, etc.) to the type before name syntax (used in C#, C, C++, Java, Dart).
Genbox
C# started as a language tightly aligned with C++/Java, but has since moved to be something else entirely that is highly capable.
I assume that free-floating functions are global functions. You can achieve something similar by "global using". Put this in a file and tug it away somewhere:
"global using static YourStaticClass;"
Now you can call all the static methods on the class everywhere.
As for the using vs. naming convention, most people use the IDE and hover the mouse over the type to see its identity. Once you get proficient with the IDE, you can do it using shortcuts. However, if you really want to prefix all types with a shorthand of the package it came from, you can do it with aliases in C#.
ngrilly
I use VSCode with the C# LSP, but I prefer to immediately see where a name comes from by reading it, rather than hovering over it. That's why I prefer to avoid global.
Regarding imports, I guess I could do something like `using c = my.namespace.ClassWithMyStaticMethods`, but I suppose it's not idiomatic in C#.
metaltyphoon
> using c = my.namespace.ClassWithMyStaticMethods
Non idiomatic? IMO, this is completely fine. Idiomatic C# doesn't mean OO all the time.
dmoney_2
Better is `using static my.namespace.ClassWithMyStaticMethods` that gets you exactly the consuming syntax you want, even though the methods still need to be static on that class.
lordofgibbons
> I assume that free-floating functions are global functions.
In most languages they're bound to some scope, like package, module, etc. I'm not familiar with C#, but I assume there it would be scoped in a namespace.
ngrilly
Yes, I'd like to be able to define functions directly under the namespace. In C#, it seems the only way to do this in to define a static method in a class, the class being part of a namespace.
moomin
Speaking as an old C# hand: 1) I don’t think static methods/classes are that big a deal. There’s a free-floating syntax for short scripts but I don’t regard this as much of a problem. There’s also the rarely used using static syntax. 2) The common convention assumes you’re using VS or Rider and can just mouse over to find where things come from. So you’re not missing anything except possibly an IDE. 3) Yeah, it is. But again, the IDE integration is great. 4) can’t argue with you there. The C-style syntax was a mistake that’s been replicated in way too many places.
ngrilly
1) It's just a bit verbose. I think I just rewired my brain around a programming style that is not OOP anymore.
2) As I wrote in another comment, my editor supports hovering with the C# LSP, but after years of reading Python, Go, Rust, and Zig, I got used to be able to see where a name comes from by simply reading it, rather than having to hover over it.
3) My problem with the verbose doc comments is not about writing, but reading.
As you wrote, all of that is not a big deal, but just feels like a step backward.
alkonaut
Yeah static types as containers for functions just means the hierarchy becomes easier. In A.B.C.D() you know A.B is a namespace, C is a type and D() is a static method. With free functions you’d be unsure if this is a free method in the A.B.C namespace or not. Doing reflection over all functions would require iterating types as well as the magical unnamed ”global type”. It’s just a special case that doesn’t carry its own weight. Especially with the newer syntax where you can omit the declaration of the type in top level programs so static void Main() is a valid program.
ngrilly
I don't see how "attaching" functions to types is easier than attaching them directly to namespaces. I don't see either why I would need to use reflection to iterate over all the functions and methods in a namespace, but I agree that if I would need that, then yes it would require adjusting the way it works today. The problem comes from the CLR where all code and data must be part of a class. C# simply mirrors that design choice. That's why C# does not offer free-floating functions. F#, which is also relying on the CLR, solved the problem by introducing the concept of "modules", in addition to the concept of namespaces. Namespaces in F# are like namespaces in C#. All code and data must be part of a module, which is part of a namespace. Under the hood, at the CLR level, modules are implemented as static classes.
mhh__
The wider problem is that to do a thing you have to start thinking about the design of IDoAThing and a implementation ThingDoer before you've even worked out exactly what to do yet.
taberiand
The C# tooling is very refactor-friendly. I commonly just build the class then pull out the interface later.
C# does want to have interfaces though, and gravitates to the common interfaces - core services - composition/DI root architecture, with lots of projects in the solution to provide separation of concerns. I think it works very well generally for business software at least, but I hear plenty of grumbling about 'complexity' so it's not for everyone.
HdS84
Just a small advertisement: have a look at automatic interface written by me. It builds your interface automatically from your class.
mhh__
I like the tooling but this doesn't change that the language has a major case of OOP-brain
neonsunset
'ThingDoer' is a naming convention from Go (I'm not a fan of the fact that we have to live with the Delphi-ism that is IMyThing but at least it's just one letter).
There is no requirement to define new interfaces except for a specific coding style in a team. It is best for most components to stay as plain and simple as possible, and for the module and component level testing to be applied with as little mocking as possible (because, most of the time, it is an anti-pattern imposed on us by what is sometimes named "London's school of testing" which is just bad practice and whoever perpetuates it should apologize).
hnthrow90348765
You don't have to do that any more, you can provide default methods for IDoAThing
penetrarthur
Honestly, every point you mention in my opinion is positive. - if you feel like using static classes and methods, you should spend more time thinking about architecture - namespaces are just what they are - in modern IDEs just write /// before a member declaration, it will insert the whole comment block for you
ngrilly
> if you feel like using static classes and methods, you should spend more time thinking about architecture - namespaces are just what they are
I don't understand what you suggest instead.
> in modern IDEs just write /// before a member declaration, it will insert the whole comment block for you
The problem is not the typing, it's the reading.
penetrarthur
Static methods in modern C# are either extension methods or some other very rare cases like mathematical functions.
The super complicated comments become readable and useful when you hover the mouse cursor over something. There are also tools that can parse those comments and create documentation.
GiorgioG
Every time I futz around with another language I go back to C# for backend work. Part of it is likely due to familiarity (I’ve been using it since 2002). I wish MS would put some additional resources into F#.
ngrilly
What do you miss in F#?
GiorgioG
Microsoft has never taken it seriously, often releasing Visual Studio with broken F# support. It's fine for something you want to tinker with (like say Elm), but not something that's easy to sell to engineering managers when starting a new project.
exceptione
Ionide and Rider are other options too. But I thought the broken F# support in VS is a thing of the past now?
Imho the bigger problem is that the C# language designer continue to not take F# into account. Structs and SUM types could be a shared MSIL story perhaps.
ngrilly
That's sad, because the language looks fantastic.
EMM_386
I've been working with C# since 2001, which is when it came out of beta stage and into production-ready.
My last greenfield product I was able to choose the stack (except the database, which I was stuck with).
Front-end? Angular, mostly because I felt it fit best with experienced .Net developers.
Back-end API layer? C#, obviosly.
So I've been working with C# for 24 years. No regrets.
arnonejoe
I’m in the same boat. I worked on a project with Microsoft Consulting Services when the .Net Beta 1.0 was released in 2001. I felt very lucky to be employed at the time (post 9/11, .com bubble bust) and also getting paid to work in the latest stack. Like you I have no regrets.
spicyusername
I recently waded into using C# to tinker with video game development using MonoGame, and I have been so surprised by how nice of a language it is to use.
With the exception of maybe Tagged Unions, it has all of the language features I could want, and the syntax is very clean and easy to read.
runevault
And they're working on Unions, although last I heard they won't make it into dotnet 10/c# whatever version is coming with it.
S04dKHzrKT
Here's the language proposal for those that are interested.
One thing I appreciate about C# and .NET is how well they resist codebase rot. In some other languages, I often encounter situations where the development environment needs to be completely recreated—sometimes due to an updated interpreter version or other breaking changes. If you've been away from the codebase for a while, chances are you'll need to make modifications just to get it running in a more recent environment.
With .NET, this issue is much less pronounced. While occasional adjustments are necessary, the environment is largely self-contained, minimizing the overhead required to get things running. As long as the .NET SDK is installed, running dotnet restore is usually all it takes—even when moving the codebase to an entirely new machine.
Some third-party libraries evolve more rapidly than others, but the core .NET libraries remain remarkably stable. More often than not, you can transition between major versions without needing to modify any code.
If I were starting a long-term project that required ongoing maintenance, C# would be my top choice. For quick scripting needs, I’d lean toward Python or PowerShell. In fact, PowerShell itself is another reason I appreciate .NET—it shares many concepts, and knowing .NET makes it easier to understand PowerShell. Plus, since PowerShell can directly leverage .NET libraries, it offers powerful scripting capabilities. I was thrilled when PowerShell became cross-platform, much like .NET itself.