moomin
4 days ago
C# dev here: it’s amazing how different this is from a Microsoft release. First off, Oracle are doing versions at approximately twice the cadence. But also, and I’m guessing this is a function of the much larger Java audience: things rarely get two preview versions in a proper release. Updates in beta versions, yes, all the time. It also feels like Microsoft are bundling a lot more into the platform and leaving less to the community. Again, probably an artifact of the different sizes of the communities. Also, the page reads like an open source “We’re finished, we’re tired.” announcement rather than the razzmatazz of a Microsoft release.
kllrnohj
4 days ago
> First off, Oracle are doing versions at approximately twice the cadence
Is that actually a good thing?
But Oracle started playing a game, for better or worse, where they decided to couple the "language version" with a single specific runtime's release schedule. For example, in "Java 27" there are exactly 0 language changes and 1 minor feature addition to the TLS library.
Everything else is OpenJDK runtime internals which don't impact the language or how you use it. So if you don't use OpenJDK (such as if you use Oracle's other runtime, GraalVM), then Java 27 basically doesn't even exist at all. Skimming the past couple of C# releases, it doesn't look like Microsoft is playing that game, so the release cadence will of course be different.
pron
4 days ago
The Java language and runtime have been co-designed as a unified platform for many years now. Virtually every significant feature has language, library, and VM people working on it, and we often don't even know when we start how much of the feature would be in the language, library, or VM. Consequently, there is no "language version" or a "runtime version". There's only a platform version, which is defined in a single spec approved by the JCP (https://openjdk.org/projects/jdk/27/spec/). This also makes things easier with regards to compatibility and evolution.
kllrnohj
4 days ago
> There's only a platform version,
And of the 4 non-preview JSRs in the Java 27 release, only 1 of them is actually part of the "platform version".
The other 3 are strictly changes to Hotspot internals with no platform involvement at all. They did not change any aspect of any Java platform in any way whatsoever. That is what I'm referring to. I'm not referring to the fact that the core library, language syntax, and runtime specs are all part of the same version. I'm referring to the fact that Hotspot specific behaviors and adjustments are also branded as being part of the platform release.
Like there's no Java 27 platform spec that says that G1 is the default garbage collector. That would of course be an absurd platform spec change. But that is still somehow a "feature" of the Java 27 release according to Oracle.
pron
4 days ago
Right. There's a "Java SE" (platorm spec) version, and a JDK version that corresponds to it, but not everything in the JDK affects or is dictated by the spec.
BTW, Java is developed "code first", which means that we first work on the implementation in OpenJDK, and then extract the relevant spec changes from it.
> But that is still somehow a "feature" of the Java 27 release according to Oracle.
It's a feature of the OpenJDK JDK, which is, indeed, the Java implementation done by Oracle (with contributions from others). The language is very careful, as you can see in the announcement: "JDK 27, the reference implementation of Java 27". The Java SE 27 spec is here: https://www.jcp.org/en/jsr/detail?id=402
jonenst
4 days ago
I wish there was a canonical write up on the governance of "java" and its history, it has changed a lot over the years (not just once I guess) and has a lot of fine prints. I find it hard to understand the hidden reasons and behind-the-scenes conflicts/compromises. There could probably be a whole book about this I guess.
hyperpape
4 days ago
You’re only counting JEPs, which are only for more involved features. There are lots of changes to the JDK apis that are used by other runtimes. See, for instance: https://javaalmanac.io/jdk/27/apidiff/26/.
Admittedly, the terminology here is almost designed to be maximally confusing, and I’ve never read a good post that laid out how everything relates.
kllrnohj
4 days ago
Fair, although even there I don't know if I'd call that "lots" at just 23 added or modified methods that aren't in preview
hyperpape
4 days ago
There are also bug-fixes and performance improvements that are not going to show on the page I linked.
I do think it’s plausible this is a smaller release. Not that this was the real point of the discussion, but I think it’s still just a good idea to have more than one release a year. It keeps things moving smoothly, and lowers the cost of missing a release, which has beneficial effects.
flakes
4 days ago
I started programming when Java 6 was relatively new. Back then it was about 3-4 years in between releases. Although I don’t write much Java any more, I’m happy to see changes shipping more frequently now.
cogman10
4 days ago
There's not really a second C# runtime. Java has several, some based on the Openjdk, but a few that are completely new like OpenJ9 and Graal.
The closest C# has is mono.
This sort of thing is bound to happen with that situation. Heck, it happens with C++ whenever a new C++ version comes out. Some C++11 features took years to make their way into all the compilers.
vlovich123
4 days ago
Graal is based on OpenJDK. OpenJ9 while using a separate JVM and JIT leverage the openjdk class path as well as the build environment and various other things.
I don’t think there’s a single alternate implementation that doesn’t leverage a good chunk of openjdk somehow
samus
4 days ago
For the simple reason that class files with JVM bytecode are the standardized intermediate representation. Therefore, duplicating the frontend is wasted effort.
pjmlp
4 days ago
Up to a point.
Embedded systems versions tend to have their own ways, which is why despite everything Android using Dex isn't a first in the Java ecosystem.
samus
4 days ago
IMHO, Dex is a historical artifact. In the past it was thought that the format provides benefits for JIT compilation because it's register based, which turned out to not be case.
pjmlp
4 days ago
Lots of "improvements" on Dalvik over J2ME was Google's marketing to sidestep Sun, speaking as ex-Nokia, coupled with the experience of Java on Symbian devices and Sony Ericson.
All these years afterwards it quite clear that there is just similar fragmentation, and implementation differences between all OEMs selling every kind of devices, and as you say the format doesn't really provide that much benefits.
What ART has going for it, are all the improvements they started on Android 7 and later, by having a mix of handwritten interpreter in Assembly, JIT compiler with cache, AOT compilation with the device on idle, and sharing of PGO metadata via the PlayStore across devices.
Ironically Windows Phone did it first, with MDIL on Windows Phone 8 followed by .NET Native on Windows Phone 10, using compilation via the Windows Store, but Microsoft fumbled the delivery.
user
3 days ago
pjmlp
4 days ago
PTC and Aicas for example.
user
4 days ago
dwaite
3 days ago
Historically, Java had a real habit of delaying new major versions for years as features hardened. Some of those features even lost relevance before their first shipping version.
So now they have a precise release cadence that features can fall into. If it is a large feature, it better get worked in incrementally (via feature previews) because it is unlikely to be able to land completely within the release window.
One could pessimistically say the faster release cadence partially serves to provide more opportunities for extended support revenue, though.
saghm
4 days ago
I didn't read the parent comment as being particularly positive in their description; it didn't sound like it was being stated as a good thing to me.
PaulHoule
4 days ago
One difference I think about is generics. Java and .NET bolted generics on to an existing system. Java used type erasure in such a way that a List<OfThat> is really just a List. Type erasure has a lot of limitations. If I am coding in Java for days I never get into trouble with it because I know how to color in the lines. But do some balls-to-the-walls metaprogramming and then it is annoying that you can't write
Expression<Integer> add(Expression<Integer> a, Expression<Integer> b);
Expression<Double> add(Expression<Double> a, Expression<Double> b);
because in the end they both look like Expression add(Expression a, Expression b)
we have ways to cope, like unerasing the types by rewriting the names... And now you've got a reason to do balls to the walls metaprogramming! Similarly if I do a lot of C# or Scala or something I will get into the habit of doing things I can't do in Java..NET on the other hand did not keep backwards compatibility, so a List is not a List<X> so .NET had a schism where some API functions use generic collections and others use non-generics which was annoying in its own way.
Something like that is how all methods in Java are virtual whereas methods in C# may or not be virtual. All-virtual is probably not the best for performance, but it is simple for understanding. You never have to think "do I make this virtual or not?" or think "is that method virtual or not and does that have consequences for how I use it?"
za3faran
4 days ago
This should address your example https://openjdk.org/jeps/218
dwaite
3 days ago
That is unfortunately more about adding another edge case for the non-reified Java generics system where it has been forced to partially reify, rather than really addressing the larger complaint.
za3faran
3 days ago
It should address the most common use case for reification. Type erasure has its advantages which we saw in the JVM ecosystem.
PaulHoule
4 days ago
I am looking forward to it, and many other things planned for Java!
AgentME
4 days ago
That's about letting you do Expression<int>, not about removing type erasure or otherwise allowing overloads based on type parameters.
gf000
4 days ago
It's one end of the same problem.
int is not an Object, so just erasing is no longer a valid approach, you need to specialize the class/method itself to use int-specific byte code.
pjmlp
4 days ago
Polyglot dev here, that uses both ecosystems, Java since 1996, .NET before it was announced to the public in 2001, only available to selected Microsoft partners.
A big difference between both ecosystems is that the Java world is like C and C++, even though Java isn't defined by ISO or ECMA, since Sun days the main implementation is only a reference, there are official documents for everything, and there is a plethora of implementations, with various kinds of JIT, GC and AOT approaches.
You can pick the real time versions for embedded from PTC and Aicas, the cloud first from IBM and Azul with finance markets in mind, the Android cousin, the various implementations for M2M gateways, copiers and phone dashboards (Ricoh, Xerox, Cisco), IoT with microEJ, and many more.
Whereas Microsoft hardly cares about ECMA nowadays, most of Mono/Xamarin is gone replaced by Core CLR and modern .NET, .NET Compact is gone, community maintained and so on.
That alone, regardless of the languages on top of JVM, or CLR, makes a big difference on the audiences when one silos themselves to a single ecosystem.
bel8
4 days ago
interesting. So less specialization on one side but also less fragmentation.
dcminter
4 days ago
Java releases used to be glacial multi-year affairs. Lots of discussion of features that then missed the release train and you knew they'd not be with you for another multi-year period.
They made a conscious decision to switch to a regular six-month cadence and it's been all the better for it. The preview-mechanism has been terrific there too, allowing half-baked features to be aired without absolutely committing to something that turns out to be flawed.
Edit: Ninja-ed by Romario77's sibling comment :)
petilon
4 days ago
> Microsoft are bundling a lot more into the platform and leaving less to the community.
This is a good thing. In Java everything has multiple community offerings, so before doing anything you have to evaluate the community offerings and decide which one to go with. If you go with the wrong one you may end up having to switch at some point, and that can be painful. This happens so often that most of the time spent when using Java is doing these evaluations and comparisons. With C# you just use the one built into .NET platform. Saves a ton of time.
PaulHoule
4 days ago
Sometimes the thing built into the .NET platform is great, sometime it is just crap but developers will use it anyway and it sets back the ecosystem.
There is this division of labor between systems programmers and application programmers and often we think systems programmers are better because they know more about algorithms and data structures and compilers and assembly language and such. On the other hand, application developers understand how to reconcile the mental model of managers and employees and customers with computers, reality and common sense and, once they get experienced, see the commonalities between all the run-of-the-mill bizapps that we are coding all the time.
Application programmers do a lot better at applications framework than systems programmers and make things like Ruby on Rails and Spring. Systems programmers make terrible things like ASP.NET MVC (I worked out a way to do MVC with ordinary ASP.NET, why couldn't they, with access to the platform internals?)
moronicles
4 days ago
[dead]
throwaway91033
4 days ago
If someone wants to create a project by assembling bits and pieces from different open source products they can, but many just go for Spring (Boot) and call it a day.
All of my projects are based on Spring and I don't really have to look outside of that ecosystem. It almost acts as an aggregator of different open source solutions and often works by abstracting the functionality so that differences are not that big. I recently switched messaging providers and didn't have to change much of my code.
rwyinuse
4 days ago
Yep, with Spring Boot development is so easy, and even decade old projects are mostly easy to upgrade. I don't have experience from C# or .NET development, but at least compared to Python and especially JS ecosystems it's so much better.
whizzter
4 days ago
Generally fairly painless in recent years, you need to divide the .NET timeline into original timeline ( .NET 1.0 -> Framework 4.8 ) and "core" lineage/timeline.
The Core (smaller, but also properly crossplatform) project begun in 2014, fairly major rewrites with breaking changes in the new releases up until 2019 (.NET Core 3.1) and 2020 (the 5.0 release that became the official major "unification" with most parts of Framework having newer alternatives and being "complete" even if 6.0 and 7.0 patched holes).
Projects started with core 3.0/3.1 in 2019 have a pretty easy and clear upgrade path without major breaking changes up until today.
It's not JS/Node volatility, and the cleanups in the language/runtime were well worth it in hindsight (still maintaining old 4.8 applications running under IIS), also 4.8 is still nominally supported so there's no immediate stress in upgrading (There are better semantics today, but with huge projects those semantic differences, mainly no lazy-loading by default are a risk).
hirvi74
4 days ago
> Python and especially JS ecosystems it's so much better.
That's a pretty low bar to beat.
PaulHoule
4 days ago
10 years ago I was working at a place that was building Python systems that had dependency graphs too complicated for pip to handle. I was able to solve the problem for my system with a "wheelhouse" system that could compute a list of wheels that could be installed to build it but the confidence of my team in Python had flagged.
I had a sheaf of notes about the problem and figured out the math to build a proper dependency resolver for Python and tested out a lot of ideas such as being able to use http range requests to get the metadata out of wheels on PyPi without having to download the whole wheel.
The problem I had no solution for though was "how to stop developers from trashing the environment that the dependency manager runs in." The data scientists I worked with had an astonishing target for wrecking anything at all. Myself I would have my poetry's environment got bad for reasons I didn't understand every few months ago.
I also found the Python community just didn't care that pip didn't really work right. The most seductive form of blub is "I can accept using things that fail intermittently." I got a job coding Java and Javascript and never built the package manager.
Then uv came along and managed to sell itself as "crazy fast" which did connect with people more than "correct". Written in rust, uv would have beaten my system in the fast department, and since it is a binary, there is no way anyone can screw up a Python it depends on -- as I see it, both technical and marketing genius!
robertlagrant
3 days ago
Before uv came along, pipenv, Poetry, and (much older) Conda all were trying to solve this problem. It's a huge problem for Python that not all languages experience, because Python packages can contain all sorts. At one point if you wanted to install Scipy you had to drag in (and compile, if I remember correctly!) Fortran, of all things[0].
PaulHoule
3 days ago
Well Java has a kind of xenophobia that really resists bringing in foreign code but Python is at it's best when it accesses wrappers around C and Fortran.
I used conda back in that period, it had a correct solver, and it was easy to manage my own packages, but it was slow in the technical sense of "it takes forever to build an environment" and slow in the business sense in that you got something curated which was not always the greatest or the latest but would, back in the day, "just work." Actually you could vendorize any software you need and have your own conda wheels, like I made wheels with different versions of CUDA drivers which are just DLLs so you could be running models with two versions of tensorflow that required two different versions of CUDA and never have to touch the NVIDIA installer.
But today it is a more "just works" experience to use PyPi instead of conda so I don't use conda.
Poetry was a big improvement over pip but I don't believe the resolver was 100% correct (like from looking at the source code) and performance was not that good, not so much because it was written in Python but because it did not have a proper cache, did not exploit concurrency. The Python way would be to use a world class SMT solver for the CPU intensive bit but when the bits hit the bus Rust is better at exploiting concurrency.
So I am happy to have uv.
MBCook
4 days ago
Yep. Anything else is probably in Apache Commons somewhere.
pjmlp
4 days ago
Which is why there are so many complaints about doing FOSS in .NET, as many companies won't use anything that isn't blessed by Microsoft, and there is an history of Microsoft cloning FOSS projects.
bob1029
4 days ago
> If you go with the wrong one you may end up having to switch at some point, and that can be painful.
https://en.wikipedia.org/wiki/Log4Shell
https://learn.microsoft.com/en-us/dotnet/core/install/window...
derefr
4 days ago
> Also, the page reads like an open source “We’re finished, we’re tired.” announcement rather than the razzmatazz of a Microsoft release.
I think this is because the JRE/JDK upstream releases are a bit like Linux kernel releases: all the major first-party feature development goes on in subprojects that maintain their own "living forks" during feature development, with the teams on these features doing PRs against the fork's own "main"; that "fork's main" having its own subproject maintainers who ensure a mess isn't made of it; and then those maintainers eventually polishing up that fork-main into a single big one-shot PR to upstream once the feature-as-a-whole is ready.
(Compare/contrast: the Linux kernel's mm, rt, and kvm feature development efforts.)
Because of this, the top-level "project maintainers" (i.e. the people who decide what gets merged into upstream main) aren't really the same people as these subproject people who care deeply about these new features. They want to ship stuff people want, but they personally mostly deal all day with requests to merge 1. small bugfixes, and 2. features so small that no JEP is needed.
But then, every once in a while, they have to deal with a request to merge one of these huge subproject upstreaming PRs. And sure, it's already heavily reviewed by the subproject's maintainers, who they trust. But they do still have to audit it and learn it and create a stabilized release path for it. "Handover" stuff. And that's tiring!
So, given that the toplevel project maintainers write the release notes, I'm not surprised they come off as weary about releases.
(That being said, for purely PR reasons, the toplevel maintainers could ask the subproject staff to contribute their perspective to the release notes of a release that merges their work? But this could also just-as-well be a separate blog post—which would probably be better for sharing. I don't think I've ever seen a centralized Java blog [is there one?] but I think the subproject teams do tend to have them.)
Romario77
4 days ago
the release cycle time was a deliberate choice.
Java tried to do fairly large updates and sometimes the release cycle would be very unpredictable as things would slip and take much longer than anticipated.
So to make it more predictable and to keep updates coming they switched to 6 months cadence with long term support (LTS) every two years.
This I think is a pretty good way of doing things, makes people who plan things figure out how to split feature development into these 6 months cycles, it made JEPs more granular and I think it made project Valhalla possible, if they tried doing it the old way it would never happen.
Splitting things in small chunks clarified what needs to be done and the path forward. It still takes very long time, but doesn't cause big incompatible changes and I think overall Java has good progress without being stalled.
dcminter
4 days ago
I remember Dolphin being a particularly painful one, and as I recall it ended up with some weird compromises (wasn't erasure supposed to avoid needing to update the bytecode format, but then annotations required it anyway? Something along those lines)
Romario77
4 days ago
yeah - they took forever, one reason being that Sun was in financial troubles and then acquisition took a long time.
Second was about licensing and Apache Harmony.
So, eventually they dropped most of the big things that were planned - Project Lambda with closures, Project Jigsaw with modularisation, Collection Literals. They eventually came back, but took a while to implement, so it was a prudent decision to make.
theandrewbailey
4 days ago
I never thought of Java being the 'move fast ~and break things~' alternative over .NET, but Java has a faster release schedule to get features out sooner.
leapingdog
4 days ago
I don't think modern Java is a 'move fast ~and break things~' environment. It's a comparatively stable platform with an enviable focus on backwards compatibility. The maintainers have talked about "last mover's advantage" when it comes to introducing new language features. Java has a checkered history when it comes to novel programming language features, so I think this is good.
Granted, the maintainers are more inclined to deprecate and remove parts of the API than has historically been the case but it is mostly obsolete things like applets. And you may need to keep a close eye on runtime flags and their effects.
MaxBarraclough
4 days ago
Move fast and break things does not describe Java well at all.
Their process is still very deliberate, they go to some lengths to avoid getting it wrong when they add new features to the standard. New features have to get through their preview phase successfully before becoming final. [0]
They're also pretty committed to not breaking existing source code or bytecode.
[0] https://openjdk.org/jeps/12 JEP 12: Preview Features
wink
3 days ago
One of the releases was that, though - either 9 or 11, with the package reorgs that broke everything. OK... it wasn't fast.
But Java 8 was stable (as in APIs, not judging its quality here) and since then it's gotten good again.
madduci
4 days ago
Seriously, how many are using always the latest releases of Java instead the LTS ones? With LTS ones you have ~2/3 years between the versions.
throwaway91033
4 days ago
We often use the latest version of Java at my work place. We haven't had any issues with upgrading, so there's no benefit of waiting for an LTS. There's no big process behind it either. The developers just quietly change the version as part of keeping the project up to date (BAU)
It may be that we are shielded from edge cases because we are based on Spring, which is probably the most tested piece of software before new versions of Java are released. But it's my impression that the risk of upgrading to a new version of Java is not the same today as it was in the past. The only advantage of an LTS is that it is supported longer, so that you can postpone the upgrade if you really want. It's not as if the intermediate releases are inferior or less safe.
varikin
4 days ago
At my last job, we only used LTS in production. Upgrading Java was always a long process, but that's more due a legacy monolithic app across thousands of servers.
You can almost think of the LTS releases as a major release and the non-LTS as a minor release, so really this could be 25.2. The current Java release schedule is to maintain a consistent and predictable release cadence instead of pushing big new features every 6 months.
peterashford
3 days ago
I'm always switching to the latest versions. Performance upgrades with no effort. Why wouldn't you (assuming you're not pinned by a dependency)
madduci
3 days ago
Privately yes, but at work getting the latest edge version isn't always the case
gf000
4 days ago
It's pretty much the opposite.
A fixed release schedule makes development more relaxed so it can be properly done, no need to rush for some release date.
If it's not yet ready, there is 6 more months to get it merged.
troupo
4 days ago
> Java has a faster release schedule to get features out sooner
While still being behind on most features?
za3faran
4 days ago
Which features exactly? Java got exhaustive pattern matching before C# (through sealed interfaces), it has switch expressions, multi-line strings, green threads and structured concurrency, is getting value types, and even type classes in the work.
jayd16
3 days ago
Even in the small list of features in your retort you had to switch to future tense.
za3faran
3 days ago
Value types are scheduled to be in preview next release (6 months). And C# does not have type classes.
troupo
4 days ago
Granted, I havent' used either for a couple of years, so my knowledge is a little rusty. Yes, some of them are "just syntax sugar", but man oh man does it make C# such a pleasant language to work with.
Used to work at a company which had services both in Java and C#, so some of Java's decisions or indecisions felt like pain points when switching between the two:
- Proper IEnumerable with proper iterators that in turn enables Linq (but in general permeates everything and is insanely easy to use and build upon). E.g. building an async service that behaves like an IEnumerable? Implement two methods.
Collection is halfway there, but I honestly cannot remember what was irking me about it in comparison to C#.
- Properties. Yeah, yeah, sealed classes, records and all that. Often you still need plain old classes.
- object initialisers. Which makes constructing anything a breeze. And on top of that you don't need manual .of methods for anything Colleciton-like if it'sa an IEnumerable.
- extension methods.
- named and optional arguments in functions
- null coalescing operator
- generics over primitive types (unless it was already implemented, I remember seeing a JEP about it)
- async/await. Yes, I know: different approaches to concurrency and all that. A lot of unnecessary verbiage could still probably be hidden behind a friendlier syntax.
- (sadly impossible in JVM to type erasure, only including this because I remember needing it many moons ago) generics metadata in runtime
- .... definitely a bunch more I don't remember at this point ...
gf000
4 days ago
At the same time, all this syntactic sugar makes the language's surface area gigantic. Like it's almost C++-level complex, and then you would have to properly understand all the interactions between this matrix of features.
That's absolutely a valid language design and many people prefer that, but I personally prefer a bit smaller language with a bit more IDE auto complete, but where you never have to think about what exactly does a line do.
(And then there is also Go that falls off the other edge of the cliff with useless if err checks spamming the code making actually functioning error handling hard)
troupo
4 days ago
> a bit smaller language with a bit more IDE auto complete, but where you never have to think about what exactly does a line do.
If you need IDE to autocomplete, then you definitely spend more time to understand what a line does ;)
gf000
3 days ago
While typing this comment I pressed/swiped on several words to finish them.
One reads much faster than they write, I don't really see a problem with easily guessable auto complete.
troupo
3 days ago
Even if you read much faster than you type, it's easier to read fewer lines of code than dozens of plumbing boilerplate.
gf000
2 days ago
Sure, we can find factors for "verbosity increase" and "difficulty to understand a line" where what you say is also true.
I think that java found a decent spot where both factors are low. It's not a particularly verbose language, especially in modern times (records, type inference, I even mention lambdas because some people live in caves), like if you do POJOs and stuff with getter setters than you get a no information increasing extra 3+3 lines of code per field and that's most of it.
Method bodies are not more verbose than other typical languages.
za3faran
4 days ago
> Proper IEnumerable with proper iterators that in turn enables Linq
Are you referring to generators?
> Properties
As far as I'm aware, it is a deliberate choice not to implement them, and I can see their point of view.
> object initialisers
I believe the same justification applies here, it's mainly syntactic sugar, and can result in certain undesired behavior by bypassing constructors where validation can happen.
> extension methods
Typeclasses are currently being explored, which are a superior approach.
> named and optional arguments in functions
Those would be nice (at least named arguments). I can see how optional arguments could complicate things.
> generics over primitive types
As you mentioned, it's in the works
> async/await... verbiage could still probably be hidden behind a friendlier syntax
The approach they took does not need any extra syntax.
troupo
4 days ago
> Are you referring to generators?
Both I guess.
Main thing is https://learn.microsoft.com/en-us/dotnet/api/system.collecti... which seems to be everywhere in the language and the library.
> I believe the same justification applies here, it's mainly syntactic sugar, and can result in certain undesired behavior by bypassing constructors where validation can happen.
This is mostly due language design. Java heavily relies on properties and provides no facilities for them. Hence the builder pattern instead of object initializers.
In C# object initializers synergize with properties: https://learn.microsoft.com/en-us/dotnet/csharp/programming-...
> The approach they took does not need any extra syntax.
You mean it needs 15 lines whete C# needs one? ;)
za3faran
3 days ago
> You mean it needs 15 lines whete C# needs one? ;)
Can you elaborate? The async/await approach is much more than 1 line when you need to switch a call between them. Whereas the green thread approach does not need anything.
jayd16
3 days ago
Good list.
- Value types is a huge one to add if we're looking at what is actually in the wild.
- Scopeless `using` declarations are nice for RAII like behavior.
- IMO C# builds are actually way way nicer than Java. Sln and .csproj files and nuget are actually a lot easier to deal with than javac/ant/mvn/Gradle. Maybe that's more a .NET thing than a C# feature.
samus
4 days ago
> - object initialisers
Probably not a good idea since they break encapsulation by exposing internals of the class. There is work on withers, which should make defining builders far simpler.
> - extension methods.
They make code harder to understand. If they ever come they would have to be declared at the top of each source file.
> - null coalescing operator
Maybe we'll get it, maybe not, but they want to first introduce proper nullable types, lest there is a risk of painting themselves into a corner.
> - async/await
There is a fork in the road, and Java has gone into the direction that leads to virtual threads and Structured Concurrency, for the simple reason that there is no simpler syntax than plain old synchronous code.
> - ... generics metadata in runtime
There are plans to add a kind of reified generics, so maybe we'll get it.
troupo
4 days ago
> Probably not a good idea since they break encapsulation by exposing internals of the class.
And thousands of manual get/set functions don't?
Thousands of lines of builders don't?
Object initializers are that plus much better handling of fields/properties that doesn't require hundreds of lines of tedious manual code: https://learn.microsoft.com/en-us/dotnet/csharp/programming-...
> for the simple reason that there is no simpler syntax than plain old synchronous code.
But it's not synchronous code, is it? It's easily dozens of lines wrangling Futures, and Thread initialisers, and Executors, and...
Java always opts out for "let the developer handle all the complexity all the time even for the simplest most used parts of the code".
samus
3 days ago
> And thousands of manual get/set functions don't?
My statement doesn't apply to mere data carrier classes. Anyway, getters and setters are an antipattern as well since one can just as well make all the fields public.
> Thousands of lines of builders don't?
With withers most of these will go away. And a class will be able to choose which things can be set, which is not the case for initializers.
> But it's not synchronous code, is it? It's easily dozens of lines wrangling Futures, and Thread initialisers, and Executors, and..
That code won't look that much different with async/await.
troupo
3 days ago
> Anyway, getters and setters are an antipattern as well since one can just as well make all the fields public.
I Java? Yes. Because of the language design, and not because of some inherent "encapsulation" or something.
Somehow `x with { a = b }` doesn't break encapsulation and offers nice DX. But object initializers? Lol
> And a class will be able to choose which things can be set, which is not the case for initializers.
The class in C# can easily chose what can and cannot be set. Because unlike Java it actually cares about things like this.
Quick example
class Test {
public int x { get; set; }
public int y { get; }
}
var t = new Test{ x = 1, y = 2 };
I can give you a hint: this will not compile.Another example:
public class Matrix
{
private double[,] storage = new double[3, 3];
public double this[int row, int column]
{
// The embedded array will throw out of range exceptions as appropriate.
get { return storage[row, column]; }
set { storage[row, column] = value; }
}
}
var identity = new Matrix
{
[0, 0] = 1.0,
[0, 1] = 0.0,
[0, 2] = 0.0,
[1, 0] = 0.0,
[1, 1] = 1.0,
[1, 2] = 0.0,
[2, 0] = 0.0,
[2, 1] = 0.0,
[2, 2] = 1.0,
};
Incomprehensible abilities for Java-land> That code won't look that much different with async/await.
samus
a day ago
You can go with a lot less code if you don't care about proper cleanup of resources.
gf000
4 days ago
> And thousands of manual get/set functions don't?
By definition, they don't.
They are verbose and hard to maintain, but if ever in the future you would want to keep the same API surface but change the internal implementation detail, they let you.
> But it's not synchronous code, is it? It's easily dozens of lines wrangling Futures, and Thread initialisers, and Executors, and...
No, it's done under the hood by the JVM. You only ever see a blocking call on a new "thread", via debugger via everything. Best of both worlds
troupo
3 days ago
> but if ever in the future you would want to keep the same API surface but change the internal implementation detail, they let you.
So do properties in C# which object initialization relies on. With significantly less manual code, or the need for tedious builder chains and withers.
`{ prop = x }` is no more encapsulation breaking than ` .setProp(x) `, but actually makes developer experience better.
> No, it's done under the hood by the JVM. You only ever see a blocking call on a new "thread", via debugger via everything. Best of both worlds
What's Java's equivalent of
x = await someFunction()
await waitForSomeOtherFunction()gf000
3 days ago
If the two calls are sequential then simply:
var x = someFunction()
someOtherFunction()
If you would have written var xTask = SomeFunctionAsync();
await WaitForSomeOtherFunctionAsync();
string x = await xTask;
then it would be: try (var scope = StructuredTaskScope.open()) { // JDK 24+ preview feature
var x = scope.fork(() -> someFunction());
scope.fork(() -> waitForSomeOtherFunction());
scope.join();
String result = x.get(); // already completed
}troupo
3 days ago
await implies async functions.
Looks like Java's "there is no simpler syntax than plain old synchronous code" is just a lot of extra manual wrangling of stuff
gf000
3 days ago
And the first two lines are an async function as they are, without any special handling.
They won't block the thread, and you can have millions of them.
Like it's no accident that c# with their goldfish attention span wanted to ship virtual threads as well next to all their millions of features.
user
3 days ago
troupo
3 days ago
Strangely enough virtually no materials on the internet show that. Everything is Executors, and Futures, and joins etc.
gf000
2 days ago
Concurrency != parallelism
I hope you know and understand the difference. Then strangely enough all my examples will make sense.
joe_mwangi
4 days ago
Typeclasses caught me by surprise. Smart move by the java team.
MBCook
4 days ago
To misquote Bart Simpson:
> Let me get this straight: we're behind the [other languages] and we're going to catch up to them by going slower than they are?
Gotta go faster if you ever wanna catch up. However, Java is also purposefully slow. Everything is extremely considered. And while it means it takes a while before you get a feature it tends to be pretty good.
hirvi74
4 days ago
I kind of wish C# would slowdown releases in some areas. I have not been a huge fan of some of the changes in the past year. I love the performance changes and bits of functionality here and there, but the syntax-sugar is getting annoying.
whizzter
4 days ago
People complain, but most of the actually used changes are in things that continually used where I find painpoints.
Not 100% on board with the collection expression changes (I found fluent Linq chains usually more readable), but they're improving painpoints so I think it'll work out in the end hopefully.
kittoes
4 days ago
Interesting take, how is optional functionality annoying? Isn't the fact that it's just sugar a huge benefit? Us old timers can simply stick to what we're familiar with.
fourseventy
4 days ago
Because unless you are the only person maintaining your codebase other people in your organization will start using the cool new syntax sugar and optional functionality. So you will be forced to deal with it as it starts showing up in your codebase.
samus
4 days ago
I'm sure that there is a tool like Checkstyle that can be used to ban features.
hirvi74
4 days ago
(GP here)
> Isn't the fact that it's just sugar a huge benefit?
My main gripe is that I cannot remember what is allowed and not allowed between multiple versions of the same language. On a daily basis I hop between apps versioned in .NET Framework 4.8 all the way to .NET 10. I have to constant remember, are nullable types allowed here? What about 'new(); vs. new Object();', new collection syntax, new switch syntax, new extensions syntax, etc..
Plus, I just find it obnoxious that the same thing can be written so many different ways. I can think of 7 ways to assign a new empty List<T>.
List<T> foo = new List<T>();
var foo = new List<T>();
List<T> foo = new();
List<T> foo = new List<T> { };
var foo = new List<T> { };
List<T> foo = [];
var foo = (List<T>)[];
There are probably more that I am forgetting. What irks me most is Java is older than C#, and from what I can remember, it is not nearly this ridiculous in terms of syntactical sugar. So, what is the true benefit behind all this sugar? It hardly saves any keystrokes in the age of autocomplete in IDEs.
I am inclined to believe most of the sugar is an attempt to make the language appeal to a newer generations of programmers. But I would argue features are more attractive than syntactical sugar. I believe Rust is truly impressive language. In my opinion, its syntax is uglier than sin, but that does not seem to deter many from using Rust.
troupo
4 days ago
Some of those ways come from just plain object initialisers. Which are amazing and sorely needed in Java.
That's why you get `new List<T> { };` Because it could be `new ComplexObject { <fileds and properties> }`.
Same for `new`.
Some come from type inference which Java also has.
That's why you can have `List<T> foo = new List<T>();` and `var foo = new List<T>();`
It's not really "7 ways to assign a new empty List<T>". It's "7 ways to create an object", and Java several of them, too.
samus
4 days ago
> Some of those ways come from just plain object initialisers. Which are amazing and sorely needed in Java.
They really aren't, and they are IMHO an antipattern since they break encapsulation. One might argue that encapsulation doesn't matter with mere data classes, but Java will cater to that use case by introducing withers.
troupo
4 days ago
> They really aren't, and they are IMHO an antipattern since they break encapsulation.
They don't. Java had to come up with the extremely verbose builder pattern for the exact same thing. And withers are basically the same tedious manual builder pattern, just with a different name.
For withers C# just has the with keyword: https://learn.microsoft.com/en-us/dotnet/csharp/language-ref...
peterashford
3 days ago
Yeah, this is the C++ kitchen sink approach and its the reason I don't favour rushing features. Never a second chance to get it right the first time
pjc50
4 days ago
I don't get this either. You can even lock the language level if you really don't want it, or you can just ignore it.
tancop
4 days ago
Most new syntax features make code more readable. For those that don't there are company style guides and `AGENTS.md`. The C++ philosophy comes down to "if it works ship it" and I don't think you're expected to use every single new feature.
ygra
4 days ago
You don't really have to use the latest C# version, though. Install the latest .NET and you get the performance improvements without usually having to change anything about your code.
Phelinofist
4 days ago
> Also, the page reads like an open source “We’re finished, we’re tired.”
I mean it's short and concise and there are additional resources that provide more detail. IMHO it's not a bad thing.
hitekker
4 days ago
> the page reads like an open source “We’re finished, we’re tired.” rather than the razzmatazz of a Microsoft release.
The vibe selects the audience perhaps.
People who are tired and just want to finish their work like the first style. People who want to do more cool work more quickly, maybe without finishing, like the second. Depends on the work, I suppose.
roflburger
4 days ago
Because there is nothing in it, that's why this release, along with majority of the recent ones drop like wet farts. How many previews of the vector API would you like?
samus
4 days ago
I read nine JEPs. Sure, some are re-Previews, but they are important since they often contain improvements from community feedback. Specifically, it would be quite unwise to finalize the Vector API before Project Valhalla. Apart from that, I'm sure that there are lots of minor visible changes that didn't get a JEP.
Anyway, not every release can be filled to the brim with new features, and people were also kinda busy whipping Project Valhalla into shape. INHO it's still preferable to stick to a predictable schedule instead of creating uncertainty in the community.
Areading314
4 days ago
> Java 27: “We’re finished, we’re tired.”
Seems about right
_the_inflator
3 days ago
I worked at a MS "fanboy" company around 2011-2013. Highly competent guys, really Senior Devs, C#, MS SQL, as well as using graph data - with one distinction: it must be MS.
Open Source? No way. Git? No, they relied as die hard MS believers on the MS software called Team Foundation or something like that, that was integrated into Visual Studio Pro - sorry, I forgot about it, I considered it kind of bloat and outdated. Also I couldn't stand the nomenclature. A project was called "Solution" - I died inside, because this sounded like utter nonsense to me, because how do they know it would be one in the end?
While JetBrains as well as Linux quickly iterated through everything and got traction as well as a cadence that overall kind of was paced around sprint cycles that lasted two or four weeks, the company finally started to break up with project management and implemented Scrum.
As the JavaScript guy, the only one, because a customer wanted a SaaS "solution" but with static web content this wasn't really dynamic. I knew one of the founders who was a managing partner and he asked me to join as Web Developer.
Overall, all were very skeptical towards me because how could someone bet on JavaScript at the time? Well I turned the argument around and said the same about C# with its closed source walled garden approach to everything relying on MS to solve their problems with no way of giving feedback while there was no real release cycle and roadmap available - hopium and copium.
Statically typed languages for the win they said, blabla. I wasn't against static types, but did pure magic in JS, that they saw me as magician and I got some fans and I found one team mate who wanted to be coached by me on JS, Ajax and stuff.
So, there you have it. History.
I think there are pros and cons to any approach as always. Both language suffer from feature creep.
C# is still tightly knit into some products from MS and there are some backwards compatibility issues to take care of that limit certain progress and need substantial change.
Java isn't that way and was near dead and went OS. That's why they moved to the current model. Former versions were also hardly changed, have a look at everything before Java Version 12 or so.
Java wasn't community driven all the time.
So, C# has its merits, TypeScript for the win, so MS won over JavaScript ironically but only on the outside.
I shocked my MS fanboy colleagues when I really gave them a shock therapy regarding security when they mocked me with the examples given by MS why JavaScript was so bad and C# would beat it. We all know the infamous type coercion examples with mixed types, arrays etc.
So I shocked them with eval function of course but then gave them nightmares and mental overload with Function.prototype.toString and new Function() trickery.
It blew their mind, there was nothing remotely available in their world. Not introspection, nothing.
JavaScript was kind of assembler like I said. Highly flexible, you need to use modules, like jQuery did but have to build your own.
So TypeScript used exactly this flexibility: compiling to JavaScript. A metalanguage.
For the true insider, JavaScript won.
mrsmrtss
3 days ago
JavaScript didn't "win" because it was a good language (it is not), it "won" because it was the only language that ran in the browser.
32oqa9
4 days ago
It's a normal open source announcement without the corporate bullshit. No fatigue. No doom. Just facts! /s
BatchJob
4 days ago
razzmatazz? Do you mean marketing lies and self aggrandizement for merely doing shoddy work?
jayd16
4 days ago
Mads Torgersen's previews and such are enjoyable and upbeat, for example.
Betelbuddy
4 days ago
>> Oracle are doing versions at approximately twice the cadence.
This has nothing to do with Oracle. All good that you hear from Java in the last few years, is the great community and good old people from Sun working at Oracle.
GrumpyGoblin
4 days ago
Someone doesn't know their Java history. Oracle bought Java 16 years ago in 2010. At that time Sun had been working on Java 7 for over 4 years with no release date in sight. Oracle trimmed the fat and released Java 7 in less than a year. And since then has kept a regular release cadence. Sun would probably still be working on Java 7.
Romario77
4 days ago
it wasn't about Oracle trimming the fat. Java 8 took 3 years to release and then Java 9 another 3 years.
They had to commit to half a year release cycles and LTRs every 2 years. Since then the releases became a lot more predictable. Whatever is not ready is not released (or is there as a preview feature).
This more agile approach is a lot better in my experience and we see that the changes made are more relevant and what people actually want.
grodriguez100
4 days ago
“The good old people from Sun working at Oracle” is now Oracle as well.