I suspect it is less about cargo culting, and more about two separate things:
First, the tooling for C# and really anything dotnet has been awful on any OS other than Windows until fairly recently. Windows is (to be blunt) a very unpopular OS in every development community that isn't dotnet.
Second, anthing enterprise is worth taking with a skeptical grain of salt; "enterprise" typically gets chosen for commercial support contracts, vendor lock-in, or astronaut architects over-engineering everything to fit best practices from 20 years ago. Saying big businesses run on it is a virtue is akin to saying that Oracle software is amazing or that WordPress engineering is amazing because so many websites run on it. Popularity and quality are entirely orthogonal.
I suppose there is probably another reason, which is the cluster fuck that has been the naming and churn of dot net versions for several years. ASP.NET, then core, then the core suffix got dropped at version 5, even though not everything was cross platform... So much pointless confusion.
I think it depends on location. In my part of the world .Net is something which lives in middle sized often stagnating companies. Enterprise around here is married to the JVM and they even tend to use more Typescript on the backend than C#. I’m not going to defend the merits of that in any way, that is just the way of things.
There being said I do get the impression that HN does know that Rust isn’t seeing much adoption as a general purpose language. So I wouldn’t count C# out here considering how excellent it has become since the transition into Core as the main .Net. I say this a an absolute C# hater by the way, I spent a decade with it and I never want to work with it again. (After decades of SWE I have fun with Python, C/Zig, JS/TS, and, no other language.)
Many developers already know Java, so it's easier to hire Java developers.
>There being said I do get the impression that HN does know that Rust isn’t seeing much adoption as a general purpose language. So I wouldn’t count C# out here considering how excellent it has become since the transition into Core as the main .Net. I say this a an absolute C# hater by the way, I spent a decade with it and I never want to work with it again. (After decades of SWE I have fun with Python, C/Zig, JS/TS, and, no other language.)
I didn't like the old C# and .NET. However, the new one is wonderful and I quite enjoy using it. More than Java or Go. On par with Python, but I wouldn't use Python for now for large web backend applications.
I tried Rust, bur for some reason I can't grow to like it. I'd prefer using C or Zig and even a sane subset of C++ (if such thing even exists).
Python is a horrible language, but it’s also the language I actually get things build in. I do think it’s a little underrated for large web apps since Django is a true work horse, but it takes discipline. C is for performance, embedded and Python/Typescript libraries and Zig is basically just better C because of the interoperability. Typescript is similar to Python for me, I probably wouldn’t use it if it wasn’t adopted everywhere, but I do like working with it.
We’ve done some Rust pocs but it never really got much traction and nobody really likes it. + I don’t think I’ve ever seen a single Rust job in my area of the world. C/C++ places aren’t adopting it, they are choosing Zig. That is if they’re going away from C/C++ at all.
I’m fairly confident that PHP, Python, JS/TS, Java and C/C++ will be what people still work on around here when I retire. Go is the only language which has managed to see some real adoption in my two decade career.
Python is the least fun language currently in use at any scale. Pretty much completely down to the lack of a coherent tool chain. When JS has better package management than you then you know you have a massive problem.
And don’t bring up mono, etc. it was a dumpster fire then and it’s only recently gotten better. It tough for any tech to shed a very long negative legacy.
GUI libraries might have some potential for improvement but I would reach for C# for any task that didnt strictly require a different language.
>Everyone working in enterprise software development has known about the power of this language for well over a decade.
What is an enterprise? Is Google not an enterprise? Is Apple not an enterprise? Is Facebook not an enterprise? What about Netflix, Uber and any other big tech company? Weren't all enterprises start-ups at the beginning?
Does enterprise mean boring old company established long before the invention of Internet, which does old boring stuff, employs old boring people and use old boring languages? I imagine a grandpa with a long white beard staring at some CRTs with Cobol code and SAP Hana.
But I wouldn't say their choice of C# is due to them being old and boring. If it was that, they'd use Java (as many do). In my eyes choosing C# signals to me that you do want good technology (again, you could have gone with Java), but want that technology to be predictable and boring. A decent rate of improvement with minimal disruption, and the ability to solve a lot of issues with money instead of hiring (lots of professionally maintained paid libraries in the ecosystem).
Effective at what?
Want GC lang with lots of libraries? Use Java.
Want GC free lang with safety? Use Rust.
Otherwise just use C. Or C++.
For me C# lies in this awkward spot. Because of past decisions it will never have quite the ecosystem of Java. And because GC -free and GC libraries mix as well as water and oil, you get somewhat of a library ecosystem bifurcation. Granted GC-less libraries are almost non-existent.
Since we discuss C# here, it is a good jack of all trades language where you can do almost anything, with decent performance, low boilerplate. It's easy to read, easy to learn and you have libraries for everything you need, excellent documentation and plenty of tutorials and examples. A great thing is that for every task and domain there is a good library or framework that most developers use, so you don't have to ask yourself what to use and how and you find a lot of documentation, tutorials and help for everything.
Java it's a bit more boiler plate-y, had a bit less features and ease of use and had many libraries and frameworks that did the same thing. Had Java been better, Kotlin wouldn't need to be invented.
>Want GC lang with lots of libraries? Use Java. Want a fast to develop and easy to use language? Just use C#.
>Want GC free lang with safety? Use Rust. Want a language which you can use for almost eveything? Web front-end, web backend, services, microcontrollers, games, desktop and mobile? Use C#.
>Otherwise just use C. Or C++. Or whatever works for you. Whatever you like, find fun and makes you a productive and happy developer. There is nothing wrong in using C or C++. Or Python. Or Haskell.
Maybe slightly. But the difference is too marginal to change languages over.
> had many libraries and frameworks that did the same thing
Maybe, but it also has many more libraries doing the one obscure thing that you need for your domain.
In a vacuum, C# is a very good language, probably better than Java (as it should be given that it was able to learn some lessons from early Java). But in the wider world of programming languages they really are extremely close to each other, they're suitable for exactly the same problems, and Java has a substantially greater mass of libraries/tooling and probably always will do.
That's basically modern-day Java, with Lombok and other tidbits. Furthermore, if I recall correctly, Java has better performance on web benchmarks than C#.
> Had Java been better, Kotlin wouldn't need to be invented.
Kotlin was invented to make a sugary version of Java, and thus drive more JetBrains sales. It got popular because Oracle got litigious. As someone who's been on the Java train for almost two decades, what usually happens, if any JVM Lang becomes too popular, Java has the tendency to reintegrate its features into itself.
> Whatever you like, find fun and makes you a productive and happy developer. There is nothing wrong in using C or C++. Or Python. Or Haskell.
Sure, assuming it fits the domain. Like, don't use Python for kernel dev or Java for some obscure ML/AI when you could use Python.
I wouldn't call Lombok "modern", more like "a terrifyingly hacky way to tackle limitations in the language despite the unwillingness to make the language friendlier" and a far cry from what source generators can do in C#
As a fan of Records, this is a punch to the gut.
The ecosystem is years and years away from using records. Almost every huge monolith decade+ project is still on Java 8, those who moved to something new still can't be liberal with them, because oh look, none of the serialize/deserialize libs can work with them because everything, to this day, abuses reflection for generating objects like a giant fucking hack it is.
Apology for the rant, but I migrated a big project to 21 early this year, am in the middle of migrating another 1M+ line codebase to 21, and the sorry state of records is such a sad thing to witness.
I give a decade before records are anything but 'a fancy feature'.
With that said - lombok is not needed at any form there either, use a c-tor with fields and make the public final. If you have too many fields in a class, it's likely a good idea to split it regardless.
In all cases dumb getter/setters are just public fields but taking more meta space (and larger byte code, the latter has some consideration when it comes to inlining)
Also, if I had 1M LOC and my serialization/communication libraries didn't support whatever I've picked - I'd patch the libraries to support it.
And I'm saying that even after writing the most of the first project (closing in on 100kLOC now) in 21, I still can't have records where the make the most sense (service boundaries) because libs and larger ecosystem don't support them.
> Also, if I had 1M LOC and my serialization/communication libraries didn't support whatever I've picked - I'd patch the libraries to support it.
1MLOC in java land is.. not unusual. And if you're talking about patching libs like jackson/jaxb/whatever, my good person, you truly underestimate how much actual work people have (where Java upgrade is a distant afterthought, I only did it because I wanted to scratch the itch and see how far I could push processes in my org), or how much impact that might have for a drive-by contribution. Updating such core ecosystem libs in java is no small feat. They are used absolutely everywhere, and even tiny changes require big testing. There is a reason you find apache libs in every single project, because they have matured over past couple of decades without such drastic rug-pull of a change.
Also I'd actively remove all apache commons as well. Even in Java8 most of the functionality is redundant.
With all that I meant it should not be really underestimation.
I am part of the dark matter, although self-initiated java upgrades already put me on the right side of bell-curve.
> Also I'd actively remove all apache commons as well. Even in Java8 most of the functionality is redundant.
I used to think that. Then I had to decompress zip files in memory and selectively process the children. Of course Java has the functionality covered in stdlib, but they require so much boilerplate, and commons-compress was such a pleasure that I was done in 10 minutes. The same goes for other apache libs too.
OTOH, I wholeheartedly agree about Lombok being unjustified curse.
But even, if you account for that, the records in Java do most of what Lombok used to do - make class externally immutable, add default `toString`, `equals` and `hashCode` implementations, allow read-only access to fields.
> what source generators can do in C#
Having had the displeasure of developing source generators in C# (in Rider), what they do is make code impossible to debug while working on it. On top of relying on an ancient version of netstandard.
I cannot emphasize enough how eldritch working on them is. While developing, whatever change you write isn't reflected when you inspect codegen code, and caching can keep old code beyond even post re-compilation unless you restart the build server, or something.
So whenever you try to debug your codegen libs, you toss a coin:
- heads it shows correct code
- tails it's showing previously iteration of code gen code, but the new code is in, so the debugger will at some point get confused
- medusae it's showing previous iteration of code gen code, but new code hasn't been propagated, and you need to do some arcane rituals to make it work.
Hell, even as a user of codegen libs, updating codegen libs caused miscompilation because it was still caching the previous codegen version.
They require 2.0, which is the only version that is actually useful, since it supports .NET Framework 4.x.v
> web benchmarks
https://www.techempower.com/benchmarks/#hw=ph&test=composite...
The Tech Empower benchmarks do seem to reflect general state of Java Web Framework ecosystem with Vert.x being they hyper fast web framework and Spring being way slower.
If you take the standard template for any of these frameworks (both Java and C# and any other language) and you add authentication etc, the real performance will be 5-10% of the numbers reported in those benchmarks. Have a look through some of the weirdness in the implementations it's wild (and sometimes educational). The .NET team especially has done stuff specifically to get faster on those benchmarks.
Could you give me a pointer or two? I wondered about that myself, especially considering the massive improvement from "old" .NET to the core/kestrel based solutions - but a quick browsing a while ago mostly left me astonished how...well, for lack of a better word, banal most of the code was.
Agreed though, lack of all kinds of layers like auth, orm etc. are sadly a drawback of these kinds of benchmarks, if understandable - it would make comparability even trickier and has the danger of the comparison matrix of systems/frameworks/libraries exploding in size. But yeah, would be nice datapoints to have. :)
The custom BufferWriter stuff is pretty neat though, although also not really something most people will reach for. And there is more, like the caching of StringBuilders etc.
But it also doesn't use the actual HTTP server to build headers, but they just dump a string into the socket [2], feels a bit unrealistic to me. In general the BenchmarkApplication class [3] is full of non-standard stuff that you'd normally let the framework handle.
[1] https://github.com/TechEmpower/FrameworkBenchmarks/blob/mast... [2] https://github.com/TechEmpower/FrameworkBenchmarks/blob/mast... [3] https://github.com/TechEmpower/FrameworkBenchmarks/blob/mast...
Puh, yeah, I see what you mean, much the stuff in [2] and [3] is rather...bespoke, especially compared to the minimal and mvc targets. Not really what I'd consider "realistic" as per the benchmark's definition.
But TBH, I wouldn't consider [1] gross, on the contrary - simple, fast, lightweight Razor templating without other MVC (or other external) dependencies isn't that unusual a use case and something I've often thought ASP.NET Core was missing (even Razor Pages feel like overkill if you just want to quickly generate some dynamic HTML).
.NET is perfectly capable of standing on its own, and if there are specific areas that need improvement - this should serve as a push to further improve DB driver implementations and make ASP.NET Core more robust against various feature configurations. It is already much, much faster than Spring which is a good start, but it could be pushed further.
I'd like to note that neither Go nor Java are viable for high-performance programming in a way that C# is. Neither gives you the required low-level access, performance oriented APIs, ability to use zero-cost abstractions and platform control you get to have in .NET. You can get far with both, but not C++/Rust-far the way you can with C#.
Yeah, except if you are working on Web servers the quality of the framework and its supporting libraries is much more important than what code could theoretically achieve. What is the point of being able to 200 mph when you only ever drive up to 30mph.
> Neither gives you the required low-level access, performance oriented APIs, ability to use zero-cost abstractions.
Java is working on high performance abstractions, see Vector API (Simd) and project Valhalla (custom primitive types).
Sure C# has a theoretical leg up (for which it paid dearly by causing backwards incompatibility with reified generics) but most of the libraries don't use low-level access or SIMD optimizations or what not.
If you meant BenchmarksGame, then it's the other way around - Java is most competitive where it relies heavily on GC[0], and loses in other areas which require capability to write a low-level implementation[1] that C# provides.
The only places where there are C calls are pidigts[2] and regex-redux[3] benchmarks, in both of which the Java submissions have to import pre-generated or pre-made bindings to GMP and PCRE2 respectively. As do all other languages, with varying degrees of "preparation".
[0]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
[1]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
[2]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
[3]: https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
Even if you prohibit PCRE2, the .NET submissions using out-of-box Regex engine end up being about 4 times faster than Java.
Surprisingly, even though .NET's BigInteger is known for its inefficiency, it ends up being more memory efficient and marginally faster at pidigits than a Java submission that does not use GMP. The implementations are not line-by-line equivalent so may not be perfectly representative of performance of each BigInt implementation.
My point being - if you look at the submissions closer, the data gives much clearer picture and only supports the argument that C# is a very usable language for solving the tasks one would usually reach for C, C++ or Rust instead.
Sure looks like it's written in Java!
Look at all the programming language implementations that provide big integers by calling out to GMP. Why would it be "cheating" when available to all and done openly? Libraries matter.
2 of 10 (pidigits and regex-redux) allow use of widely available third party libraries — GMP, PCRE, RE2 — because there were language implementations that simply wrapped those libraries.
https://benchmarksgame-team.pages.debian.net/benchmarksgame/...
It’s not that easy. I assume other programs hide the use in macros and libraries, in ways far beyond my simple understanding.
Where there are few enough programs that readers should check that the programs they compare seem appropriate for their purpose.
Why? Did you mean both use intrinsics or both don't?
> Sometimes, you just want to see
As-it-says, look for more-secs less-gz-source-code -- probably less optimised.
But it’s not that easy.
Filters some but maybe not all and maybe filters some wrongly.
If you don't think it's appropriate to compare the pi-digits and regex-redux programs, simply ignore them and compare the other 8!
Lombok is exceptionally backwards. You don't need getters/setters; and you should know how to try hashCode (and equals).
...and records exist
C# is better designed lang, has really strong tooling and ecosystem and well designed std lib
Not sure about that. Maybe there are? If you do web or mobile apps, C# would be an excellent choice. Go would be also an excellent choice for web.
For AI I wouldn't use C#. Even though it has excellent ML libraries, most research and popular stuff is done using Python and pytorch, so that's what I would chose.
For very low level, I'd take C or Zig. But I don't know many startups who are into very low level stuff.
My only issue with many of the improvements in C# is that all of them are optional for backwards compatibility reasons. People who don't know or don't care about new language features can still write C# like it's 2004 and all of the advantages of trying to modernize go out of the window. That means that developers often don't see the need to learn any of the new features, which makes it hard for projects to take advantage of the language improvements.
Instead of new platform libs and compilers simply defaulting to some reasonable cutoff date and saying "You need to install an ancient compiler to build this".
There is nothing that prevents me from building my old project with an older set of tools. If I want to make use of newer features then I'm happy to continuously update my source code.
Some examples of companies/products not implementing backwards compatibility are Delphi and Angular. Both are effectively dead. .NET Core wasn't backwards compatible with .NET Framework, but MS created .NET Standard to bridge that gap. .NET Standard allows people to write code in .NET core and will run in .NET Framework. It's not perfect, but apparently it was good enough.
Companies usually won't knowingly adopt a technology that will be obsoleted in the future and require a complete rewrite. That's a disaster.
But the compiler only consumes syntax (C#11, C#12 C#13 and so on) so I don't see why the compiler that eats C#13 necessarily must swallow C#5 without modification
public Patient Patient { get; set; }
The same thing with modern code would be public Patient? Patient { get; set; }
Because with the new C#, objects are by default not null. Fortunately there is a compiler flag to turn this off, but it's on by default.As a guy who has worked in C# since 2005, a breaking change would make me pretty irate. Backwards compatibility has its benefits.
What issues do you have with backwards compatibility?
As a class library example (which is contrary to what I said earlier about .NET compatibility vs C# compatibility) is that it was a massive mistake to let double.ToString() use the current culture rather than the invariant culture. It should change to either required passing a culture always (breaking API change) or change to use invariantculture (behaviour change requiring code changes to keep old behavior)
I would imagine that's a carryover from the Win32/Client-Server days when that would have been a better choice.
Is that annoying? Yea. Is that annoying enough to force companies to collectively spend billions to look through their decades old codebases for double.ToString() and add culture arguments? Also keep in mind, this is a runtime issue, so the time to fix would be much more than if it were a compile issue. I would say no.
Just the move to Unicode (i.e. from 2007 to 2009) took some work, but otherwise I can't think of any intentional breaking changes...? In fact, it's one of the most stable programming environments I know of – granted, in part because of being a little stagnant (but not dead).
I've been using Delphi since Delphi 3. The only really breaking change I can recall was the Unicode switch. And that was just a minor blip really. Our 300kloc project at work took a couple of days to clean up the compiler errors and it's been Unicode-handling ever since. It's file integration and database heavy, so lots of string manipulation.
Most of my hobby projects didn't need any code changes.
In fact, the reason Delphi was late to the Unicode party was precisely because they spent so much time designing it to minimize impact on legacy code.
Not saying there hasn't been some cases, but the developers of Delphi have had a lot of focus on keeping existing code running fine. We have a fair bit of code in production that is decades old, some before y2k, and it just keeps on ticking without modification as we upgrade Delphi to newer versions.
The market has been ignoring Delphi for that long. It probably peaked with D5, once they changed their name from Borland to Inprise, it was over.
I hear it's still somewhat popular in Eastern European countries, but I heard that several years ago.
But is also not a trivial task.
Microsoft probably added these features to push the language into new niches (like improving the story around Unity and going after Arduino/IoT). But it's of little practical appeal to their established base.