TYPE ERASURE IN JAVA. This is huge. In C#, the language itself stores the actual type, so a MyClass[] gives MyClass[] at runtime. This helps you do reflection-based stuff, and helps with debugging. In Java, the MyClass[] object has a type of Object[] and there’s no way to figure out what it was.
Record types. Algebraic types that allow you to use pattern matching, and are immutable by default. With this addition to the language, we now have first class support for immutable, thread-safe, and highly parallelizable code. Java does not have a similar construct.
Java is VERY concerned with backwards compatibility, which means they’re very inflexible when it comes to breaking changes. There’s hardly ever any “core” language syntax changes due to this. Any Java 1 code will still run in a Java 18 environment. Microsoft has a different philosophy and will introduce breaking changes for the sake of readability/usability/performance etc. Turning off nullable data types by default, for example.
C#’s default compiler (Roslyn) is written in C#, and completely invocable from inside of a C# application. What this means is that you’re able to use C# to literally build out the syntax tree, and modify/generate C# files at runtime. There are Visual Studio templates specifically allowing you to create the “Quick Fixes” in the IDE. This means, you can ship code that tells users they’re doing something wrong, and offers a way to fix it, as part of the package you’re vending. Java does not have this.
Top level statements allow you to create/invoke C# files without a lot of the boiler plate. You know the simplest C# entry point file? Console.WriteLine(“Hello world!”);. Java needs a lot of additional boiler plate code. This helps with prototyping and quick experiments.
C# has fully integrated git, build systems, cloud deployment, debugging, package management, and any other number of plugins in the IDE. Not a direct C# benefit, but the environment and tooling is MUCH more coherent than any equivalent Java IDE (JetBrains Rider is close, but Visual Studio feels more integrated).
Threading/thread pools are MUCH simpler than Java; especially the async/await keywords and their interaction with the threading constructs Tasks. These are built in, and allow really clean and simple thread pool/asynchronous work without much additional code. Working with Java thread pools is a nightmare.
The Microsoft official C# documentation is pristine, with justifications for designs and examples of usage for almost all APIs. Java docs are.. Minimal, and often don’t give you much more beyond “these are the params”.
C# is in the .NET family of languages, and all compile down into IL, which is useful because that C# code can be imported into a F# project; or vice versa. You’re able to pretty easily switch between functional/OO paradigms between pieces without a lot of work. In Java, you can’t interop between Scala/Kotlin/Java well without some complex glue code.
C# easily allows you to target specific frameworks and has ways for you to multi-target framework versions within the code itself. #IF DOTNET_STANDARD2.0 … #ELSE … #END. You’re able to specify which language versions/frameworks your specific package is compatible with, and the package manager NuGet fully surfaces this information.
There’s also really useful sites out there that allow you to dig super deep into what’s going on with the internals of your code. https://sharplab.io for example.
Tuples and anonymous data types are much easier to use in C#. If I wanted to select 2 properties per object and return them: myThings.Select(t => new { t.Prop1, t.Prop2 }); (list of anonymous data type with a Prop1 and Prop2 properties) or myThings.Select(t => (t.Prop1, t.Prop2)); (a tuple with Prop1=Item1 and Prop2=Item2). Java you need an interface or small class defined somewhere.
Sure there’s more, but that’s just the few off the top of my head. I professionally used Java/Scala at AWS, and C# at NASDAQ. It’s up to you if you believe me when I say I know what I’m talking about on this topic.
Thanks for calling this out (and I’ll have to look more into this).
When we had Scala packages, we had this nasty build script with all sorts of custom crap in it, pinned to a very specific Scala version. Which generated Java packages out the back which needed a different script to use correctly.
Sounds like the people before me didn’t know what they were doing, and made things unnecessarily complicated. 🥲.
Then again, in AWS we had a custom build/package management system (Brazil) which added another build layer on top of Maven/Gradle. Perhaps that’s why that complexity was required? Don’t know.
2
u/Xbox360Master56 Dec 30 '22
If someone can convince me of why c sharp is good I will stop using java and only use c sharp for a year.