I haven't kept aware of changes to Java in the last decade, but the things I didn't like about it then were:
1. The overall architecture (with the JVM) made it slower than the equivalent C# code.
2. C# really started embracing modern language features at a time when Java was kind of languishing (lambda functions, async patterns). Java seems like it's been in perpetual catch-up since then.
(Not OP, disclaimer, I work for Microsoft and this is only my opinion).
> I haven't kept aware of changes to Java in the last decade, but the things I didn't like about it then were:
It's almost a shame. I am genuinely impressed with the gains the team has made in both, language aspects as well as JVM technology. They have some brilliant people working on it and I love to hear their talks (Brian Goetz and Mark Reinhold, mostly).
But I suppose I would say the same about .Net, it's just that you guys have much less public exposure of your internal reasoning.
I've seen the gains in Java; the main things that would close the gap are not yet there in Java. .NET code, especially when tuned, still has significantly more knobs in your code to tune and make faster. An example would be proper generics with value types together means less boxing in generic code in general overall but there's a lot more I can think of. I've seen almost 50% of gains, particuarly when doing math like code, of moving away from Java to .NET especially if the jump to C/C++/Rust is too much for the team in question due to other requirements.
There's more to developer experience than that. Your comment even demonstrates one of the differences: The .NET library compared to a bunch of different Java frameworks.
C# 1.0 was pretty much Microsoft Java, but since then, C# has evolved into its own, more powerful thing, while Java has stayed much more conservative over the years.
I'm not sure it is more powerful but it might be more ergonomic. The strange part about both (today - it made sense 20 years ago) is the whole bytecode thing. That should go away imo.
What’s wrong with bytecode? Using something abstract helps with porting between OSes and architectures. .NET supports compiling to native executables, but only a limited subset of projects is supported, because reflection is not available in native AoT mode.
I think this was a fair statement up until a couple years ago, but right now I am lamenting the actual progress in C# and CLR technology.
I think the progress on Java and the JVM has been nothing but impressive. Not only compared to the baseline to where things were 10/15 years ago, but simply how much stuff comes out each year and how well-thought it all is.
Frankly, it's an inspiration for my private and professional projects.
I wouldn't call this a silly question at all. But having recently converted my intro data structures course from Java to C#, I can talk about why C# might be better. I have programmed regularly in both languages for the last 15 or so years (in addition to regularly programming in TypeScript, Scala, and F#).
Java is fast and reasonably safe. It has a lot of software (especially OSS) software. Its package system (Maven and the like) is ok, but not great. The language occasionally gets new features, but change is slow.
To a first approximation, C# is a lot like Java, so it is relatively easy to switch. But C# is, hands down, a better language. The most obvious thing that a developer might notice that that C# does not force you to be extremely verbose like Java, although you can code in the Java style if you like.
Having switched my course from Java to C#, the most obvious "win" was the fact that, every lecture, I would delete some slides that explained painful Java corner cases to students. For example, Java's implementation of generics. Boxed types are necessary, and explaining them to students who have never seen any form of polymorphism before is difficult. After an entire semester of deleting a handful of slides each lecture, I have save _three entire lectures_ worth of corner cases!
Some C# niceties:
* Everything is an object, even value types! So our favorite `ToString` and `GetHashCode` methods, etc, are all there.
* Generics work as you would expect with very few weird corner cases. No boxed types because... everything is an object!
* The last two facts mean that you also get generic arrays, which are fantastic (and, incidentally, are also _implemented_ in C#, which is super cool).
* By default, reference types are not nullable. This is a little bit of a pain for an intro data structures course (we turn them off), but it is a great idea for commercial programming.
* switch statements work the way you would expect a modern switch to work, and in some cases they even do exhaustiveness checking like a functional language.
* Speaking of... LINQ!
* In general, the standard library is also better organized. Interfaces start with "I". Collections libraries have been carefully designed and learned many lessons from Java. A good example of an improvement over Java is the IEnumerable<T>/IEnumerator<T> class, which is simpler than Java's Iterator<T>.
* Type inference is limited compared to a functional language, but it is dramatically better than Java. Being able to write `var` is wonderful.
* Properties are really nice, and the shorthand syntax for property getters/setters saves a lot of time.
* C# has a rich set of value types, including structs. Java may have added something like this, since I remember the Scala people hacking away on it, but it is used pervasively in C#, and you can make very fast data structures that take advantage of spatial locality. Rolling one's own hash table implementation in C# is actually kind of fun.
* .NET's runtime reflection capabilities are amazing. All of my autograders make extensive use of reflection instead of forcing students to compile with interfaces; this gives them a degree of freedom in implementing things.
* NuGet is a million times easier to use than Maven.
The downside is that C# is definitely not as fast as Java, in particular when the runtime is starting up. I remember how painful Java startup used to be, so I am optimistic that this will improve eventually.
Anecdotally, my students this semester are demonstrably more capable programmers after a semester of C# than a semester of Java. It might just be that I got lucky with this group, but I have been teaching this same course (except in Java) for the last 7 years, and this feels like a real effect.
This is interesting. I've been away from the high-code world for a while and instead of going back to Java, I might try out c#. Thanks for the writeup.
I'm not new to C# myself and I have been writing a hobby game project in it for the better part of 2 years. I know the C# features pretty in-depth by now, and while you can definitely make an argument that C# has more and better features, I found that Java has greater synergies in its features.
Don't get me wrong, there are some features like "abstract static" in interfaces which give C# superpowers... until you realize that this only works one layer deep. Or the non-break switch expressions, which require a return type. Lack of an equivalent to Java's "Sealed Classes" (that you can switch over). Or that you can't validate primary constructors up until recently.
Lack of value objects are definitely hurting, but JEP401 addresses this and is available as preview as of now. I am absolutely blown away by the depth of their value-narrative and I think they uncovered something much deeper than "value or not" with gradual performance gains based on gradual constraints.
But I absolutely see the value of C# in teaching. Java works more via libraries and convention, whereas C# has ingrained many concepts directly into the syntax level.
But maybe I am a Java fanboy, haha. I even prefer the Erasure of Generics, the times it has complicated my code in C# is much higher by now than I ever thought it would be.
> Generics work as you would expect with very few weird corner cases. No boxed types because... everything is an object!
Took me a moment to realize you meant that 'Java has corner cases because everything is an object' but yes.
Will also add the 'advantage' that for value types (i.e. struct) the generics are 'specialized' for the type, in certain cases you can use that for performance optimizations. (although it can have downsides.)
> The last two facts mean that you also get generic arrays, which are fantastic (and, incidentally, are also _implemented_ in C#, which is super cool)
And, fun side note, the generic arrays actually existed before real generics (and we get fun hacks in the VM as a result!)
.NET does still have funkiness around Array Covariance tho, which sometimes can be a pain.
> By default, reference types are not nullable.
This is a newer feature and great, however it requires people to (1) use libraries that properly do it and (2) requires you to have the right tag in the csproj to flag the NRT warnings as errors. I've yet to see a shop that has adopted (2) as a default.
> In general, the standard library is also better organized. Interfaces start with "I". Collections libraries have been carefully designed and learned many lessons from Java. A good example of an improvement over Java is the IEnumerable<T>/IEnumerator<T> class, which is simpler than Java's Iterator<T>
Yes and also the sugar around yield syntax to do generators.
> Properties are really nice, and the shorthand syntax for property getters/setters saves a lot of time.
I still remember getting called into a Dev Manager's office, he's a JVM guy and he's goes into this overview of Lombok and how the JVM folks want to use it and he asks what I think and I'm like "Gee wow give me a moment I thought Java had AutoProps by now". (I think it was the first time he was impressed with C# as a language lmao, He and later I were disappointed in .NET's lack of a good set of thread pool abstractions...)
> .NET's runtime reflection capabilities are amazing. All of my autograders make extensive use of reflection instead of forcing students to compile with interfaces; this gives them a degree of freedom in implementing things.
That is so freaking cool and I love it. Profs like you made college fun back in the day.
> NuGet is a million times easier to use than Maven.
Truth; every time I have to do a thing in JVM dealing with maven feels like I need a goat or chicken to make anything work right.
> The downside is that C# is definitely not as fast as Java, in particular when the runtime is starting up. I remember how painful Java startup used to be, so I am optimistic that this will improve eventually.
We have AOT and R2R nowadays, I'm not sure if it's 'JVM Fast' for something like a webservice but unless you're pulling in something like an ORM it's typically fast enough I can't observe a difference as a user for utility apps/etc... Curious what examples you have in mind?
The thing that always turned me off about Java are the IDEs. Besides Java doesn’t have anything like LINQ. I would rather have an ecosystem backed by Microsoft than Oracle.
I haven't kept aware of changes to Java in the last decade, but the things I didn't like about it then were:
1. The overall architecture (with the JVM) made it slower than the equivalent C# code.
2. C# really started embracing modern language features at a time when Java was kind of languishing (lambda functions, async patterns). Java seems like it's been in perpetual catch-up since then.
(Not OP, disclaimer, I work for Microsoft and this is only my opinion).
Ah, got you.
> I haven't kept aware of changes to Java in the last decade, but the things I didn't like about it then were:
It's almost a shame. I am genuinely impressed with the gains the team has made in both, language aspects as well as JVM technology. They have some brilliant people working on it and I love to hear their talks (Brian Goetz and Mark Reinhold, mostly).
But I suppose I would say the same about .Net, it's just that you guys have much less public exposure of your internal reasoning.
I've seen the gains in Java; the main things that would close the gap are not yet there in Java. .NET code, especially when tuned, still has significantly more knobs in your code to tune and make faster. An example would be proper generics with value types together means less boxing in generic code in general overall but there's a lot more I can think of. I've seen almost 50% of gains, particuarly when doing math like code, of moving away from Java to .NET especially if the jump to C/C++/Rust is too much for the team in question due to other requirements.
C# and Java might be similar technologies at some level but they not similar developer experiences at all.
How so? It striked me that the .Net library and Java frameworks like Spring or Quarkus are virtually identical.
There's more to developer experience than that. Your comment even demonstrates one of the differences: The .NET library compared to a bunch of different Java frameworks.
3 replies →
C# 1.0 was pretty much Microsoft Java, but since then, C# has evolved into its own, more powerful thing, while Java has stayed much more conservative over the years.
I'm not sure it is more powerful but it might be more ergonomic. The strange part about both (today - it made sense 20 years ago) is the whole bytecode thing. That should go away imo.
What’s wrong with bytecode? Using something abstract helps with porting between OSes and architectures. .NET supports compiling to native executables, but only a limited subset of projects is supported, because reflection is not available in native AoT mode.
2 replies →
.NET needs runtime code generation for some of its core features, like generics. Bytecode makes this much easier.
1 reply →
I think this was a fair statement up until a couple years ago, but right now I am lamenting the actual progress in C# and CLR technology.
I think the progress on Java and the JVM has been nothing but impressive. Not only compared to the baseline to where things were 10/15 years ago, but simply how much stuff comes out each year and how well-thought it all is.
Frankly, it's an inspiration for my private and professional projects.
I wouldn't call this a silly question at all. But having recently converted my intro data structures course from Java to C#, I can talk about why C# might be better. I have programmed regularly in both languages for the last 15 or so years (in addition to regularly programming in TypeScript, Scala, and F#).
Java is fast and reasonably safe. It has a lot of software (especially OSS) software. Its package system (Maven and the like) is ok, but not great. The language occasionally gets new features, but change is slow.
To a first approximation, C# is a lot like Java, so it is relatively easy to switch. But C# is, hands down, a better language. The most obvious thing that a developer might notice that that C# does not force you to be extremely verbose like Java, although you can code in the Java style if you like.
Having switched my course from Java to C#, the most obvious "win" was the fact that, every lecture, I would delete some slides that explained painful Java corner cases to students. For example, Java's implementation of generics. Boxed types are necessary, and explaining them to students who have never seen any form of polymorphism before is difficult. After an entire semester of deleting a handful of slides each lecture, I have save _three entire lectures_ worth of corner cases!
Some C# niceties:
* Everything is an object, even value types! So our favorite `ToString` and `GetHashCode` methods, etc, are all there. * Generics work as you would expect with very few weird corner cases. No boxed types because... everything is an object! * The last two facts mean that you also get generic arrays, which are fantastic (and, incidentally, are also _implemented_ in C#, which is super cool). * By default, reference types are not nullable. This is a little bit of a pain for an intro data structures course (we turn them off), but it is a great idea for commercial programming. * switch statements work the way you would expect a modern switch to work, and in some cases they even do exhaustiveness checking like a functional language. * Speaking of... LINQ! * In general, the standard library is also better organized. Interfaces start with "I". Collections libraries have been carefully designed and learned many lessons from Java. A good example of an improvement over Java is the IEnumerable<T>/IEnumerator<T> class, which is simpler than Java's Iterator<T>. * Type inference is limited compared to a functional language, but it is dramatically better than Java. Being able to write `var` is wonderful. * Properties are really nice, and the shorthand syntax for property getters/setters saves a lot of time. * C# has a rich set of value types, including structs. Java may have added something like this, since I remember the Scala people hacking away on it, but it is used pervasively in C#, and you can make very fast data structures that take advantage of spatial locality. Rolling one's own hash table implementation in C# is actually kind of fun. * .NET's runtime reflection capabilities are amazing. All of my autograders make extensive use of reflection instead of forcing students to compile with interfaces; this gives them a degree of freedom in implementing things. * NuGet is a million times easier to use than Maven.
The downside is that C# is definitely not as fast as Java, in particular when the runtime is starting up. I remember how painful Java startup used to be, so I am optimistic that this will improve eventually.
Anecdotally, my students this semester are demonstrably more capable programmers after a semester of C# than a semester of Java. It might just be that I got lucky with this group, but I have been teaching this same course (except in Java) for the last 7 years, and this feels like a real effect.
This is interesting. I've been away from the high-code world for a while and instead of going back to Java, I might try out c#. Thanks for the writeup.
I'm not new to C# myself and I have been writing a hobby game project in it for the better part of 2 years. I know the C# features pretty in-depth by now, and while you can definitely make an argument that C# has more and better features, I found that Java has greater synergies in its features.
Don't get me wrong, there are some features like "abstract static" in interfaces which give C# superpowers... until you realize that this only works one layer deep. Or the non-break switch expressions, which require a return type. Lack of an equivalent to Java's "Sealed Classes" (that you can switch over). Or that you can't validate primary constructors up until recently.
Lack of value objects are definitely hurting, but JEP401 addresses this and is available as preview as of now. I am absolutely blown away by the depth of their value-narrative and I think they uncovered something much deeper than "value or not" with gradual performance gains based on gradual constraints.
But I absolutely see the value of C# in teaching. Java works more via libraries and convention, whereas C# has ingrained many concepts directly into the syntax level.
But maybe I am a Java fanboy, haha. I even prefer the Erasure of Generics, the times it has complicated my code in C# is much higher by now than I ever thought it would be.
> Generics work as you would expect with very few weird corner cases. No boxed types because... everything is an object!
Took me a moment to realize you meant that 'Java has corner cases because everything is an object' but yes.
Will also add the 'advantage' that for value types (i.e. struct) the generics are 'specialized' for the type, in certain cases you can use that for performance optimizations. (although it can have downsides.)
> The last two facts mean that you also get generic arrays, which are fantastic (and, incidentally, are also _implemented_ in C#, which is super cool)
And, fun side note, the generic arrays actually existed before real generics (and we get fun hacks in the VM as a result!)
.NET does still have funkiness around Array Covariance tho, which sometimes can be a pain.
> By default, reference types are not nullable.
This is a newer feature and great, however it requires people to (1) use libraries that properly do it and (2) requires you to have the right tag in the csproj to flag the NRT warnings as errors. I've yet to see a shop that has adopted (2) as a default.
> In general, the standard library is also better organized. Interfaces start with "I". Collections libraries have been carefully designed and learned many lessons from Java. A good example of an improvement over Java is the IEnumerable<T>/IEnumerator<T> class, which is simpler than Java's Iterator<T>
Yes and also the sugar around yield syntax to do generators.
> Properties are really nice, and the shorthand syntax for property getters/setters saves a lot of time.
I still remember getting called into a Dev Manager's office, he's a JVM guy and he's goes into this overview of Lombok and how the JVM folks want to use it and he asks what I think and I'm like "Gee wow give me a moment I thought Java had AutoProps by now". (I think it was the first time he was impressed with C# as a language lmao, He and later I were disappointed in .NET's lack of a good set of thread pool abstractions...)
> .NET's runtime reflection capabilities are amazing. All of my autograders make extensive use of reflection instead of forcing students to compile with interfaces; this gives them a degree of freedom in implementing things.
That is so freaking cool and I love it. Profs like you made college fun back in the day.
> NuGet is a million times easier to use than Maven.
Truth; every time I have to do a thing in JVM dealing with maven feels like I need a goat or chicken to make anything work right.
> The downside is that C# is definitely not as fast as Java, in particular when the runtime is starting up. I remember how painful Java startup used to be, so I am optimistic that this will improve eventually.
We have AOT and R2R nowadays, I'm not sure if it's 'JVM Fast' for something like a webservice but unless you're pulling in something like an ORM it's typically fast enough I can't observe a difference as a user for utility apps/etc... Curious what examples you have in mind?
The thing that always turned me off about Java are the IDEs. Besides Java doesn’t have anything like LINQ. I would rather have an ecosystem backed by Microsoft than Oracle.
Does Java have real generics yet?
[dead]