This is perhaps a naive question, but are there many machines that need more than 64bits of address space?
One of the things that jumped out to me about that changes, was that I assume that this will allow for unsafe pointer math. I suppose this is a low level api, but I thought that was an interesting choice.
Even leaving alone the fact that we may wish for a computer architecture that could theoretically mmap(), say, the internet... things like CHERI are gonna bring fat pointers back.
> Creating a brand-new API today which cannot handle pointers wider than 64 bits seems a bit short-sighted
2^64 can address over 16 petabytes. I’m not sure when I’ll be working on that scale, but n by the time it happens, Java can introduce new data types like BigLong to handle it.
It does allow for unsafe pointer math, I have some examples here where I've ported io_uring to use native Java Foreign Memory API with no external headers/bindings:
It seems like you are using the `MemoryAddress` object. The article says that api was removed in 20. I may be misunderstanding what you are doing though :)
In Java 19, there was a notion named MemoryAddress used for “pointers to memory” and function
addresses. In Java 20, MemorySegment::address returns a raw memory address in the form of a
long rather than a MemoryAddress object.
>This is perhaps a naive question, but are there many machines that need more than 64bits of address space?
I thought a potential CPU of the future could have 128 bit "word size" for integer calculations and as a side effect also 128 bit pointers to reuse registers/instructions for both of them (just like today with 64 bit CPUs, indeed you don't need to map the entire address space but pointers are still 64 bit because it's the CPU's word size). And then address space layout randomization in a future OS could choose to map very high address ranges for the process, which can't be represented with Java's long.
This is probably posted in jest, but there was a time - not so long ago - where folks firmly believed nobody would need more than 16 memory bits, and even 1 Gigabyte of storage was considered outlandish.
Things have gotten exponentially larger in the meantime... with your average home computer going from < 1GB of RAM to 8GB and ever increasingly larger (my cell phone has 12GB of RAM and 512GB of storage for what it's worth).
Having storage ranging in the Terabyte category is simply the norm, and things like Petabytes of storage are rapidly becoming more accessible for average users.
Saying "X is enough" - ever - in computing is foolhardy.
but there was a time - not so long ago - where folks firmly believed nobody would need more than 16 memory bits
This is not true, no one seriously thought 65 KB was ever going to be any sort of a limit. If you're talking about the Bill Gates quote, it's basically a myth that never happened or was taken WAY out of context. Bill Gates himself has given interview where he talks about the entire state of released and upcoming computers of that time and exactly what everyone thought was going to happen and what actually did happen.
No, it was not just Gates that thought this. Look around you, all of your old tech was designed for smaller numbers. Even IP addresses were designed with "we'll never need more than X", and look at the mess we're in today.
Every time someone in tech has said "that number is large enough", the number gets surpassed in no time.
So while 64 bit memory addresses seems way more than ample today, it will not be forever. That was the point...
No, that's not how it went. People were not stupid and lacking any foresight in the past. Constrained storage space has been a concern since Charles Babbage's analytical engine, that is since forever in computing. No one ever thought let's stop at 16 bit pointers or whatever and it will be enough for the rest of time. It's an engineering tradeoff to make the best of the technology available at the time. Pointer sizes are not just a number, they correspond to realities down to the electronics and physical design of your system. Longer pointers mean larger address bus, larger registers, more transistors on your chip that won't be available for something else. They are more wasteful if you don't actually have that much memory to address. It's incredibly naive to think today's standards were even a possibility decades ago.
> No, that's not how it went. People were not stupid and lacking any foresight in the past
It truly is in so many cases. Not stupidity, but perhaps hubris. The same hubris that says nobody will need more than 64 bits today. Given time, 64 bits will fall waste to 128 bits and more.
The people who designed IPv4 truly thought the number of IP's would be more than enough forever. They literally had no concept that one day your average person would own multiple computing devices and require multiple IP's just to get through a normal day. They were very wrong, and found out in only a few year's time.
The only constant in tech is our assumptions today will be wrong tomorrow. Assuming "X" is big enough is foolhardy in just about every scenario.
You realize that limitations like 16 bit addressing was because of the extreme limitations of the time right? The 6502 can address 65KB of memory, had 13 address modes, 55 instructions and was made out of 3,510 transistors. Modern CPUs have over a million times the transistor count.
Every year was another iteration of these limits being updated, no one ever thought any of these numbers were going to stay static. It took 1MB of memory just to have a 24 bit color frame buffer at NTSC resolution.
IP addresses were set at 4 billion when you could print out a list of known computers and put it in a binder and we still use it today.
This idea that people had a general lack of foresight was completely untrue. What people did with limitations like 3,510 transistors is astounding.
Upvote from me. I have been at 32GB of RAM for more than 5 years. I am genuinely surprised. I'm basically a big corporate programmer that runs Microsoft Outlook (surprisingly low memory), a giant (8GB RAM) IDE, and a squillion Google Chrome tabs. I struggle to think how/when I will need more than 32GB RAM. I have 64GB at home from a COVID-era new build, only because it seemed short sighted to "only" buy 32GB RAM in 2021. I have never once come close to needing it. :)
That said, I completely agree with your sentiment about "X is enough". What has changed in the last 20 years: When we double RAM/storage/network now, the increase is enormous. It does feel like GPUs are still in the insane growth period. Very soon they will be more powerful and have more on-board RAM than whole rest of the computer.
An internet search tells me there are somewhere between 10^76 and 10^82 atoms in the universe. We must not rest until all atoms are mmap-able. That should require at least a 273-bit length type to be safe. Since we need a power of two, 512-bit length. This size also gives us a little room for fat pointers.
It doesn't seem there are many orders of magnitude more subatomic particles. 3 quarks in a proton. At most O(10^2) protons in a atom. So it should all fit comfortably in a 512-bit type.
* As for photons, this estimate finds 4*10^84 photons since start of universe:
>But why do you need the length of a pointer to also be a power of two? Are you addressing the bits in the pointer?
Indeed. The entanglement code will crawl without easy direct addressing of the bits. We wouldn't want the universe to run even slower, would we now? It would also make the development emulator impossible to run leading to even more bugs and missed deadlines.
6502: 8-bit registers / 16-bit address space (1975-)
68000: 16 / 24 (1985-1992 then 32/32)
ARM1: 32 / 26 (1985- 32/32 in 1992 and finally 64/64 in 2011)
X86: a complete address space mess but lately 57-bit:
The morale of the story is humans are insecure fragile little creatures, half of us are blind and the other half are pessimists because we can imagine what the truth/future looks like. Lies only last the time you can use energy to hide them.
Anyhow the arch of binary evolution is over; to build a MMU that can adress 64-bits of data is probably impossible with electrons. Just going from 64GB to 256GB is hard and makes things slower! Caches appeared in 1985, so since then the bottle neck has been RAM latency:
The biggest server from Oracle currently has 16 TB of RAM, good luck multiplying that by the difference in energy content per mass difference between oil and uranium (1.000.000x).
And good luck paying your energy bill. 64-bit RAM would consume 5120W * 1.000.000 = 5GW (you want 5x nuclear power plants with that server?)
Personally I'm staying on 32-bit for my ARMv8 cluster, my processes are limited to 4GB RAM each but since I only have 8GB of total RAM there is ZERO difference in switching to 64-bit as it effectively halves the RAM.
The morale of the story is humans are insecure fragile little creatures, half of us are blind and the other half are pessimists because we can imagine what the truth/future looks like. Lies only last the time you can use energy to hide them.
I made a comment about the virtual memory space of most desktop CPUs in use. I have no idea what you are talking about, did you mean to reply to me?
Anyhow the arch of binary evolution is over;
I don't think these words together mean anything.
to build a MMU that can adress 64-bits of data is probably impossible with electrons.
It's strange to call something impossible when it has already been done.
Real question: What is a reasonable solution? Java has strictly defined primitive types: The largest integral type (long) is 8 bytes/64 bits. Please remember that Java does not have typedef, so it is not as simple as hiding the solution behind an opaque typedef that is #define'd at compile time.
More likely: If 128-bit address space really takes off, they can create a new largest integral type long128 that is 16 bytes/128 bits, and either extend the existing MemorySegment, or create MemorySegmentLarge to allow for bizarrely large address spaces, like up to 1024-bit.
Another one that people like to pick on Java about: Arrays are limited to max size of 2^31-1 (non-negative part of a 32-bit signed int). To rephrase your question: <<So the API assumes arrays can't be larger than a 32 bit signed int?>> Yeah, I guess.
The Array limitation is easy to deal with (in my opinion). If you're needing arrays larger than Integer.MAX_VALUE, then you're probably doing something wrong to begin with. Usually you want to partition your data and maintain multiple arrays in some reasonable way hiearchical way, if you're getting that big. Or more likely, at that point, you're building your own memory structures using a ByteBuffer (and possibly in the future, MemorySegment).
Point is, your reply is exactly right. Arrays can't be 64-bit large? Yeah, I guess.
I read this post a couple of times before it hit me: Your comment about Arrays and "doing it wrong" actually works without trolling the original question. Your main point: The question isn't hardly useful vis-a-vis arrays. However, for pointers -- if you really have 128-bit pointers -- then, yes, you are screwed and that interface/impl won't work. Excellent reply!
I thought of something like IntPtr in C# (native size int). Although, to be portable, JVM would have to disallow doing pointer math on it, to make IntPtr fully opaque.
But that is just a raw representation of a pointer, what you actually pass and use as a pointer is not long values, but MemorySegments (formerly MemoryAddresses) — so the actual size is just an implementation detail.
Plus Panama won’t go stable until Valhalla, which is necessary to actually have a “long long” in the language.
Outside of actually understanding, in detail and not just in rough strokes, what they are going on about, are there more educated layman's interpretations possible other than the polar opposites of "why do java people insist on making everything that complicated when others have so much simpler FFI" and "wow, it seems like they are addressing nuances that others haven't even thought of (or chose to knowingly ignore)"?
There's nothing particularly special about LTS releases. According to Ron P, they are basically arbitrarily decided by sales and marketing: https://news.ycombinator.com/item?id=33039539
There is a bit: GraalVM bases itself on LTS releases in terms of features, and Android also somewhat follows them but lags behind way too much (Android 13 came out this year and prides itself on getting up to date with JDK 11).
> Oracle's sales arbitrarily selects some feature versions for which to offer an LTS service, and other companies follow their choice
This does not seem to be strictly true. The release cadence is scheduled, with mostly predictable release times.[1][2]
The idea was, if some feature didn't make it's way into this release, it'll just get into the next release (which is only a few months away). Very similar to how the Linux Kernel does releases - arbitrary in features, but not arbitrary in time.
And while Oracle may retain a great deal of influence over the OpenJDK project, Oracle is not the OpenJDK project anymore. There are a lot of other voices to be heard that decide when and what is done.
> BTW, [other companies] can choose to offer LTS even for releases that have already been made and retroactively make them "LTS releases." There's absolutely nothing special about them
He's right about this. However, the reality is most companies offer the same LTS as was scheduled, with extra paid support for anyone willing to pay (and be stuck on) a regular release.
> And while Oracle may retain a great deal of influence over the OpenJDK project, Oracle is not the OpenJDK project anymore
While there is surely (very welcome) other voices as well, I am not sure I can agree with this statement given that 95+% of OpenJDK development is done by people working for Oracle.
And the projects that tend to be what pushes the platform forward are mostly led by folks at Oracle: Amber (Brian), Loom (Ron), Panama (Maurizio), Valhalla (Brian), Leyden (Mark), etc.
The commitment from OpenJDK to continue to support the LTS release for a number of years longer than the non-LTS releases is pretty significant to a lot of companies using Java.
Ron is outspoken and knows the issues better than most. But he can be blunt on his perspectives and definitely does not represent the whole ecosystem or the majority perspective on all things Java.
For _many_ enterprise users, there is indeed something particularly special about the LTS releases. Even if it's just a marketing term, it's still important to realize that organizations value stability, and the LTS releases can offer that at a different comfort level (and price point).
Yes, LTS was dreamed up as a way for Oracle to make money on open source Java. But the other non-Oracle vendors (equally important to the ecosystem) very much have similar offers of support that Oracle provides.
I'm glad for the model, frankly. And I'm excited about Java's future. LTS releases helps smooth out discussions with CTO types about how to live with Java. Developers can use the latest-greatest and be sure to target a particular LTS version for deployment. Finally Java seems to be moving again.
When pron comes in here and smacks us down with his replies, that's OK, I'm comfortable with my perspective. :)
The operative word is perspective. He represents the perspective of the Java Platform Group where most of the project leads and key developers work (see my comment below). We certainly get that many in the industry see LTS releases as something special, but from the perspective of those that build the platform, they are just another release. This is an important distinction because thinking LTS is special might lead to the inaccurate notion that a non-LTS release is somehow of lower quality, which I hear surprisingly often.
And glad you are excited about the future of Java and the model itself! Most of this work is funded by the LTS model which was designed to give companies the flexibility to decide their upgrade strategy. Lots of teams want to move quickly and get new features, while others just want the app in the corner to be stable for years to come.
I don’t think they are arbitrary from the perspective of a business. LTS JDK builds offer bug and security fixes for an increased amount of time compared to non-LTS versions.
Unless your business is keen on upgrading the JDK every 1.5 quarters it’s simply easier to rely on LTS versions.
The LTS support guarantees are even true for non-Oracle JDK builds. For example, Amazon Coretto also follows the LTS cycle.
I touched Java in school and rarely since. Is it the kind of language where you can be production-level productive with just a text editor and CLI, or do you need an IDE to manage everything?
The last time I poked at it, there were just so many config and generated files and so much complexity that it felt like I must use an IDE that hides a layer of “magic”.
Or am I just confessing ignorance and this isn’t a thing and it’s no more complex and magical than Rust or JavaScript or Python?
Using an IDE for Java will, in general, make you orders of magnitude more productive. Not because of generated files or anything like that, but because it can recommend methods, auto-fill in details, add imports, etc. That kind of things saves a lot of time over the long run.
Depends on when you last touched Java. Lambda's (Java 8) have significantly reduced the ceremony needed to do things you'd use anonymous inner classes for. Java 14 introduced records, which makes building simple immutable data objects trivial.
It's still a fairly verbose language, but it's miles from where it was 10 years ago.
The language has definitely evolved a lot from then. But so have the major frameworks. While not perfect, building a web app in spring boot is a whole world better than doing the same using Java-6 era frameworks.
The strong typing system in Java means the recommendations and general code assistance is much more accurate and powerful than that if scripting languages
Java's libraries, coding conventions and culture made it verbose more than the core language itself ever required. Starting from scratch and eschewing "good practices" it was always possible to write much leaner code. Get rid of getters and setters, make every field public and final, use anonymous classes to implement interfaces inline, that sort of thing. Obviously wouldn't pass a code review at any "serious" shop ten years ago. But look at Java 20 now, with immutable records and closures and type inference? Well now that code style is now ok! But obviously my ten year old PR is still not approved...
Java is much much shorter than Go, which oddly enough never gets this “complement”. So, take these boilerplate claims for Java with a grain of salt.
But to actually provide an answer, records shorten the language to a great degree in my opinion, there is also type inference with `var`, so on a local scope you can write really short code. The main method is still chatty, but it’s not like you actually have to write all that many times, plus it is just psvm for most IDE users.
Yes! I work programming in Go. I like it a lot - its a very pragmatic language. But I couldn't believe that people who derided Java for verbosity were raving about Go. It's pretty good, but the boilerplate is extreme
You can use a text editor. I’d look at the hello world Java application to see how simple it can be. It’s the frameworks that are responsible for config files, generated code, etc. That said, it’s much easier to manage large applications with an IDE.
Well, you certainly can use it with just an text editor. However, due to the maturity of the language and platform, the IDE support of Java is pretty much unsurpassed and you would certainly be quite a bit more productive if you used an IDE like IDEA or Eclipse.
In terms of complexity, it really depends on what you want to do. Using a powerful framework like Spring can entail some config (albeit much less than it used to). Also you would typically use a build tool like maven or gradle to manage dependencies, build artifacts, etc.. Especially maven can be a little arcane. But another major upside of the aforementioned maturity is that there are reams of docs and stackoverflow answers which will almost certainly contain solutions for any problems you might encounter.
> reams of docs and stackoverflow answers which will almost certainly contain solutions
This is both a blessing and a curse. Some answers and docs are decades old and although still work, are not “fashionable java” (think streams, for instance).
And streams are part of the reason checked exceptions are now unfashionable. Java doesn’t infer that a generic function arg should affect the caller’s exception signature.
This is why I gave up on Java years ago. There seemed to be a lot of cruft left in the language and libraries that you were just supposed to know to not use anymore. I guess for backwards compatibility, but as a learner it's rather frustrating.
Has that gotten better recently? It's been years since I've toyed with it.
A lot of cruft has been split into modules, so you no longer have AWT/Swing/smartcardio/etc. in your classpath unless you want it.
A lot of cruft is still there; Date, File, InputStream/OutputStream, sun.misc.Unsafe, and the entire legacy reflection API are the bunch that stick out to me. Newer releases are actively mentioning their legacy status in documentation, and there are certainly JEPs to remove them or make them opt-in/opt-out.
If you look at OpenJDK internals, or even the foreign function/memory APIs as described in the article, it looks almost nothing like the Java I learned on and wrote for several years. Most of the Panama API is piggybacking on additions to the language made post-JDK9 or so, such as MethodHandle, VarHandle and @PolymorphicSignature methods. So I'd say the language and runtime is evolving nicely, even under the thumb of Oracle.
But the old ones aren’t superseded the same way Date is, though. You are perfectly fine using them and in fact will perform similarly well due to Loom (which has actually reimplemented them on top of async APIs)
I occasionally have to touch Java though I'm far more at home in e.g. Python. If you don't mind, a consist mention off the top of your head of things that people in my position should know about, as we Google our Java issues. I'm not cutting and pasting Stack Overflow answers, but even so they often do form the basis of ideas of the code that I write in the end. So pitfalls and modern replacements for ancient practices would be appreciated. Thank you!
> Or am I just confessing ignorance and this isn’t a thing and it’s no more complex and magical than Rust or JavaScript or Python?
This is it. There are things which are better in Java than in the other ecosystems you mentioned (e.g. dependency management) and there are things which are worse (the language is more chatty, maybe the designs tend to be more convoluted, but this differs project to project). Even enterprise Java has come a long way, it's different to what it has been a decade ago, it's definitely more lean.
Every sane developer uses either Jetbrains' product for JS, Python or Rust, or they use VS Code, which, after installing all plugins to reach the same productivity as with Jetbrains, becomes an IDE as well.
> Every sane developer uses either Jetbrains' product for JS, Python or Rust, or they use VS Code, which, after installing all plugins to reach the same productivity as with Jetbrains, becomes an IDE as well.
You seem to vastly overestimate the usage of IDEs with scripting languages. In my experience, the vast majority of developers working with scripting languages such as JavaScript, Python or Rust, still use plain text editors such as Vim or Sublime Text. They find these editors to be more convenient and faster than IDEs.
Even people who are on VS Code seem to be using only the built-in language support for scripting.
> In my experience, the vast majority of developers working with scripting languages such as JavaScript, Python or Rust, still use plain text editors such as Vim or Sublime Text.
Definitely not in my experience, most people I know use VSCode, which I wouldn't call a plain text editor (not necessarily an IDE either though). Most people will use the plugins for each language since those are auto-recommended when you open a new file in that language, such as Pylance for Python, and most people will click "install recommended plugins" and call it a day.
Vim users are few and far between in my experience, and Sublime Text even more so, most everyone has migrated to VSCode at this point that I know of.
I tend towards simple GUI text editors (Sublime and gedit), but I'm not really a developer. That said, I do use VSCode for anything that has to touch a git repository because screw trying to manage that on the command line. I wonder if that's what tends to push people towards an IDE if they weren't already using one.
Me too! Although I am playing with Sublime merge lately - it is pretty handy for creating branches off of specific commits, looking at diffs across branches etc.
The nice thing is being able to use the IDE or a simple text editor and be productive. There are times where a text editor is just right. There are times where the IDE is just right. And with Java... well, very rarely does the text editor fit.
I don’t know, I can count on one hand all the websites that still just sprinkle a bit of vanilla JS written in notepad.. JS frameworks absolutely need an IDE, so does python frameworks.
But surely, for advent of code scripting you don’t need it, but neither does Java.
Java doesn't require any config files, and the only generated files are .class files that are equivalent to .o files in C.
There are all kinds of things that you can pile on top of it, usually for managing big projects. Those can seem arduous when you're at the Hello World level. If you got introduced to those it will seem daunting and unnecessary (and for many projects, it is).
But basic Java is no more onerous than Python or JavaScript. About the only difference at that scale is that Java requires type notation, but no more so than C.
And I wrote Java for over a decade with vi. IDEs make it better, but they are not necessary. (And good ones are free anyway.)
You will need to use an IDE to be productive in Java. One thing that Java does better than just about any other language though is it's maintainable. A codebase in Java can exist for decades and not become unmaintainable no matter what lowest bidder IT services contractor works on it. That's because the language makes it hard to write obfuscated spaghetti code and the static typing allows for deterministic refactoring of bad code. That's something you can't easily do in JavaScript.
This is an interesting comment. When you say "maintainable", I would agree but for different reasons. It would say a single owner for most of the ecosystem (Sun->Oracle) makes it exceedingly stable. (Yes, I know IBM has a parallel universe, but little used compared to Oracle's.) Think about it: A single vendor provides the whole stack: compiler, debugger (including remote!), standard library (immense, well-documented), virtual machine, and IDE (NetBeans). There is also a small army of well-paid, highly skilled developers employed by Sun->Oracle constantly working to improve this ecosystem. Probably, the only thing they don't provide is a build system. They originally wrote Ant, but then let free in the wild. Also, no segmentation faults, full exception stack traces, and mature decompilation tools make it incredibly simple to debug -- even the hairiest legacy libraries. With the exception of Microsoft's C#/.NET, I cannot think of any mature equivalent. Note: Above, I never mentioned the open source community (Maven Central Repo, etc.). I won't touch that because the quality varies wildly.
And, yes, I agree 100% about your reference to low cost developers. From an enterprise view, it is cheap and easy to find (low quality and) low cost developers to maintain legacy Java software.
You also wrote: <<... static typing allows for deterministic refactoring of bad code. That's something you can't easily do in JavaScript.>> Most JavaScript devs would immediately reply: "Oh, use TypeScript for that." As I understand, you can incrementally upgrade a legacy JavaScript project to TypeScript, then slowly add types. Also, I have refactored lots of Java code that uses Object as a substitute for C's void*. That type of code is so difficult to understand without a debugger. Also, very difficult to refactor due to limited typing.
I’m not sure I agree with the single owner part — it surely helps to give that “final touch” stability, but Java’s huge advantage is being an actual standard with an insane number of very independent implementations. Sure, most actual code will run on basically OpenJDK with minor modifications, but features are not added willy-nilly and the semantics are not just “whatever our single compiler outputs”.
I don’t know if this is true, I’ve seen some truly awful spaghetti g with a dozen modules to implement a trivial web api and it was indecipherable. This was for a “tech” company as well, not just some random internal app (it was built by the sales org though, which explains it).
Java after JDK 17 is a completely different language, almost like the difference between Javascript pre-ES6. It got:
- Pattern matching
- Sealed types
- Records (immutable, succinct data-classes)
- Multiline strings
Among other things. It's almost as nice to use as Kotlin, and I say this as a huge Kotlin fan. Its pattern matching in most recent releases is actually more powerful than Kotlins, since it allows deconstruction-bindings in patterns.
I feel like this is going to be to kotlin's disadvantage going forwards as languages features are slowly added into Java, they will be more 'complete'.
Java can never be Kotlin without breaking a lot of backwards compatibility. That is the "edge" a newer JVM language like Kotlin enjoys.
Since Java's history is very focused on not breaking things (and folks got really grumpy on the few occasions something has been broken), Java cannot ever match the feature pace of languages like C# either.
But the folks writing Java code (most of you here on HN by all metrics), mostly don't care. They enjoy backwards compatibility and stability far more than new features. The overwhelming majority of newly written Java code is targeting Java8 still - which doesn't use any of these new features anyway.
Backwards compatibility is also why things like lambda's and streams are the way they are in Java (and most FP folks would sneer at), and things like Records took years to release (still technically in the Preview stage).
The advantage Kotlin has, and the reason it's growing in popularity in backend development is you get all the FP tasty features you want right now, but maintain near drop-in compatibility with existing Java libraries and frameworks. This was the most brilliant move by the Kotlin designers in my opinion...
Adding features doesn’t mean breaking backwards compatibility, I can only think of modules since Java 8 that can maybe be.
What Kotlin features are possible because of that freedom ?
Genetics can be an example I can’t say it’s impossible for Java to add in out refied keywords
I don’t know, in theory replacing types with ‘var’ would work just as well for Java, the advantage (or more like elegance) of ident: type syntax comes from a parser perspective.
> Java cannot ever match the feature pace of languages like C# either.
That's by deliberate choice. They are going down the route of having the last mover advantage. Lots of people have complained about C#'s kitchen sink type of approach for example. And the more features you have, the more chance that they won't fit together neatly and cleanly.
A couple of examples that come to mind, Java's pattern matching/destructoring and upcoming string templates (JEP 430) are much more fully fledged compared to their Kotlin counterparts.
It also has the advantage of being the platform language. Now that we have virtual threads on the JVM, async/await immediately becomes irrelevant. However, Kotlin now has to maintain coroutines even though the platform offers a better way of doing things.
I would rather that they would give more support to F#, and improving the story on the Common Language Runtime between all existing MS languages, instead of rebooting the whole experience into C# Language Runtime.
F# goes right up with D as "most under-rated/under-recognized language of all time"
A lot of its features for functional programming got swallowed up in later C# versions, and it's the Red-Headed Stepchild of the CLR (let's pretend VB.NET doesn't exist).
MS allows it to exist but it's a second-class citizen on the CLR, and, I think, always will be =(
their numbers are simple .... C# has millions of developers, VB.NET 100ks and F# 10ks. They put their focus where their users are. They presented a slide deck once about that.
And F# was created as a research project and is a lot more community driven than C#. So if Microsoft starts putting more people onto that, I think a part of that community will also scream that they should stay out.
There were no users when C#, VB.NET and Managed C++ (replaced by C++/CLI on .NET 2.0), likewise there were no users per se when WinRT was created with another tooling and API surface than its Win32 and .NET counterparts.
I know those numbers, and can even refer to the blog post they were presented, if a big company like Microsoft wants people to use language XYZ, they can make it happen if management cares about it.
However they aren't caring enough to sort out the GUI civil war, so why would the .NET languages by any different, regarding coherent management across the board.
> As a C# advocate I have to say, that the C# design team is doing an excellent job. The amount of syntax I see literally 1:1 taken over by dozen other languages is really impressive and evidence for that.
That would be the case for pretty much any language that has lots of features (provided that most of those features aren't completely terrible). A good design (at least for a mainstream language) also strives to minimise the number of features, not adding everything you can but only adding things you absolutely need. In the case of C#, many of its features are not widely adopted, and Java in particular will never adopt them.
Java's philosophy has always been to wrap an innovative runtime in a conservative language that only adds features late, after they've proven their worth elsewhere and when most mainstream programmers are ready for them, with the realisation that every added feature adds a cost to learning the language. That strategy has worked very well for Java, but .NET has a different strategy (a more adventurous language built on top of a less adventurous runtime). We'd rather spend two years thinking about how to avoid adding a new language feature than spend six months adding it. This "last-mover" strategy has helped us maintain our philosophy and keep the number of features small compared to C#. We strive to only add features that have a big bang-for-the buck and that, preferably, solve many problems at once, rather than add many features, each addressing a relatively small problem. For example, virtual threads have allowed us to avoid adopting async/await; records are allowing us to avoid adopting properties, and will likely help us avoid adding named and default parameters as a separate feature (which, in languages like C#, Swift, and Kotlin breaks binary compatibility/separate compilation).
I posted that in parallel. C# tries to be both, a system and application language. Java does not try that. Therefore, they can skip all the memory related topics quite quickly. And that wades out like 80% of the average joe unused features.
> Java cannot ever match the feature pace of languages like C# either.
Thank God. Don’t get me wrong, C# is a cool language but languages suffocate under so many features, most devs will simply never ever learn most of them. And some of these features while invaluable in certain rare cases, I would rather prefer a better, more fundamental feature that takes more time and single-handedly solves for many situations.
Unfortunately modern languages really like to throw in everything they have seen from other languages ever, and even with very smart language designers these features will inevitably tangle (khm, swift).
C# tries to be a system language (for writing servers, runtimes, and even operating systems) AND an application language (for writing your favourite apps). So you have now a huge feature set which is focused on efficient memory handling and then you have another feature set on writing nicely applications (think pattern matching etc).
While WinDev keeps ignoring such improvements and rather doubles down on the C++ / COM combo, including forcing everyone else to deal with writing .NET bindings to those APIs.
CsWinRT and win32metadata are still quite far from a great usability experience.
It's actually crazy what you can do with C# as far as systems programming nowadays.
I recently wrote a database buffer pool with it, allocating raw aligned memory and directly casting bytes from DB files into in-memory struct pointers.
It's very nearly a systems language in terms of capabilities.
> The overwhelming majority of newly written Java code is targeting Java8 still - which doesn't use any of these new features anyway.
Java 8 users are now a minority. Some libraries still target it (although Spring 6 targets 17 as the baseline), but most Java code is in applications.
> Java can never be Kotlin
Java doesn't want to be Kotlin because it aims at a much wider audience. Back in the nineties James Gosling laid out a strategy of an innovative runtime wrapped in a conservative language that only adds the most beneficial features, and only after they've been successfully tried in other languages, and this has worked very well.
Also, the Java language has the advantage of controlling the runtime, which allows us to add a smaller number of features, which are more powerful (e.g. compare records with data classes, or virtual threads with syntactic coroutines), while Kotlin can neither change the runtime nor have a significant impact on the ecosystem, and so is more limited in what it can achieve. Moreover, Kotlin's features are increasingly mismatches with the evolution of the platform.
Nevertheless, we are happy that the platform offers more feature rich languages to the minority of developers that do prefer them (or languages with radically different approaches, such as Clojure), so the platform can cater to programmers with different language preferences.
I don't think it can be Kotlin, but I don't think it needs to put a serious dent in Kotlin adoption, as it just needs to stop driving people away so hard and then the friction to do something different will keep people in Java if Kotlin is say, only 30% nicer. See for example coffeescript getting limited by ES6.
IMO Kotlin is barely nicer than Java currently. Java has for the most part implemented better or equivalent versions of a lot of Kotlin's features (e.g. virtual threads, pattern matching, sealed classes).
The last things missing are properties (which should be coming with reconstructors), and nullable types. For me, nullable types are not worth the switch.
All that being said, I don't think the languages are mutually exclusive. As a JVM developer you retain all your knowledge of the JVM and it's standard library. Lastly, a language doesn't have to be the dominate language on a platform to be usable and employable (just look at Scala).
Kotlin has made its pack with the Chocolate Factory, as such they need to now live with the consequences of being a language whose main purpose is to write phone apps where compatibility with Java isn't taken seriously.
I'm still waiting (agonizingly) for pattern matching in switch to actually land as a non-preview feature. We're looking at a fourth preview in Java 20 (March 2023), so we probably won't get it for realsies until at least Java 21 (September). And that's assuming the associated record patterns JEP is also ready to go after just two previews; it seems like they want them to land together.
Many of these projects actually wait for Valhalla before finalizing. It would be a real shame if they couldn’t all boil together a bit to get it absolutely perfect.
Does anybody think that the Java collection api needs to be re-written to catch up with Kotlin's or Scala's? And String should not be String but a collection of characters? And arrays should not be arrays but a collection? And records are not the only thing that can be decomposed but arrays, lists, EntryMap (tuple2) ... should be decomposable as well?
I do know people who write Java in vim, with some plugins installed to give them IDE-like features. I've tried it, but, frankly, it's just so much easier to use something like IntelliJ IDEA, that it feels silly not to. The non-IDE ways of doing things are still pretty unpolished and missing features, while the IDEs are incredibly polished at this point.
I think the whole config/generated files thing is for old-school J2EE "enterprise Java". Most of the frameworks I've used have just involved writing code. Sure, sometimes you need a config file, but that's pretty normal -- most of the time I'd rather specify things like port numbers and logging configuration in a separate config file, rather than hard-code them in the app themselves. If you stay away from the old-school Java Servlet frameworks -- or use a framework that builds on top of servlets and hides the complexity -- then you don't have to deal with that crap.
The build ecosystem is a bit more fragmented than Rust (maven or gradle or sbt or...), and the build tools do require a bit more boilerplate to configure, for the most part (especially maven), but it's not too bad. JavaScript, IMO, has some of the most inscrutable build systems I've ever seen, so I don't think that's comparable to Rust, or even Java. Maybe the complexity of Java build systems is similar to Python, though in different ways.
The recent releases of Java have added a lot of quality-of-life improvements to the language, so it's a lot more pleasant (and less verbose) to write Java than it used to be. I still prefer something like Scala (2; haven't tried 3 yet), but it's a lot easier to build a team around Java than Scala.
Of course you can use Java with an editor like Vim or Emacs for simple projects but I would advise to use an IDE like IntelliJ IDEA for bigger projects, e.g. for its support for refactoring. As a statically typed language the benefit of an IDE will be much better than for Python or JavaScript. The same is true for Rust. An IDE helped me to get much more productive because it can show the inferred types without invoking the compiler all the times.
Speaking language agnostically… If you’re developing prod projects without an IDE, you are likely not being as productive as you could be. Can you frame a house without a framing nailer? Sure. But why? You’ll spend 30x the time and the quality won’t be as good.
I worked take a second look at IntelliJ and Eclipse; learn the keyboard shortcuts. Modern Java is incredibly well put together.
Java compilation and packaging is actually probably the most clear, well documented of all languages.
Most of the tooling is provided, and it's coherent and robust.
Ultimately - both Maven and Groovy, which are used for production level build and packaging, are a 'weird'. But getting going with them is relatively easy.
Java has introduced the concept of 'Modules' - which if you don't get straight in your head, can be confusing, but ultimately it's not that bad.
Compilation is relatively fast as well.
The 'IDE' tends to 'hide a lot of things' in ugly ways - that is true. All of the JAVA IDEs are weird about that. However - because Java is a well maintained language, the IDE's can be powerful and are actually worthwhile. Jetbrains being one of them.
Sadly, Java on VSCode is a bit of a mess.
On Android, Google has introduced a bunch of odd conventions and complexities which I feel are unnecessary.
Once a code base gets big enough to be larger than a handfuls of files, a text editor just won't be able to keep up with the refactoring/reorganizing capabilities of a statically typed language managed by an IDE. This feature of Java alone makes it well worth it (over say JavaScript or Python), despite whatever other issues the language has.
There's a project called JBang that aims to provide a much simpler DX when working with Java projects. For basic projects, the experience is almost Go-like.
Java is just a painful language. At that level of abstraction you would expect to work purely on business logic, yet Java makes you just focus on the boilerplate and lacks completely basic features such as tuples, real generics, async/await, anonymous types and more. Spring is another huge pain point, it's slow and verbose in comparison to Go or even .NET. Java is not even close to Kotlin, that's why it was invented in the first place, to not make you want to shoot yourself in the head. Needless to say, I don't see any real use of Java in 2022 and beyond.
So decide, if you want to work on business logic, why do you want to further dig your grave with async/await, which is by definition an implementation detail?
Also, sprint is not slow at all, especially that servers are very famously IO-heavy. Nonetheless, you can expect better performance for these with project loom.
Going to copy my Reddit comment over to HN because I think it's valuable:
---
One of the coolest things that's been worked on (by this same author, no less!) isn't even in the article!
Per has written a pretty-printer for MemorySegments and ByteBuffers that can hex-dump memory or render memory/buffers as their "struct" representations given some MemoryLayout.
You can also customize it with your own printers, it's wicked cool and helps so much to debug buffers when working with them.
What do I mean by that? Have a look at this comment for an image of a raw memory structure layout I represented with MemoryLayout, and the pretty-print rendering of it:
How would this work with an IDE? As part of a debugger in the IDE? Isn’t it nice that you could throw an Error with this stuff?? I don’t write Java but I do end up writing pretty printers whenever I work on a project with interesting binary data zooming around between memory, network, and disk, and it’s cool that this framework builds it in. I would love if all languages had a pretty printer this nice for their struct types.
Because language usefulness pretty much scales with stdlib features. Tools then get built around that pretty printer, instead of everyone having their bespoke implementation. The Java ecosystem is many things, but you cannot say it isn't homogenous. Dependency injection ? Every single project that has gone on to use annotations will be using the same @Inject. And so on, for many, many featyres.
> Every single project that has gone on to use annotations will be using the same @Inject
Except when they use @Autowired. (Ackshually aside, I do agree with the sentiment of your post. The standard library is arguably one of Java's greatest assets)
I take issue with the thing being a part of HexFormat. It should use hexformat, optionally. What if I want to dump the memory to binary or octal instead? The hexformat class itself could have been an adjustable BaseNFormatter :(.
Sorry for the tangent, it had to get out somewhere and I did not think it was worthy of an email in the actual review thread : - )
Is it possible for me to type-pun a struct from shared memory? I don't want to read the bytes and convert them to a long or whatever. I want to apply a long operation to some memory space. Is that doable in Java with Panama?
Yes, for FFI jextract can also auto-generate helper classes, so some C struct named tb_cell with a field named ch typed int, you could access its fields like tb_cell.ch$get(memorySegment) and tb_cell.ch$set(memorySegment, value).
Of course you are not required to do FFI, you may want to use this API to speed up some very memory-sensitive operation. Then you can define your own memory layout, specifying precisely endianness, alignment, padding, anything, and access it comfortably through these APIs.
The last time I seriously used Java, JNI was the only way to access code outside of the JVM. I haven't kept up much, but this does seem cool. Anything that lets me use code I didn't have to write in Java is a feature of Java I'm excited about.
I've never played with Java's FFI, but now that we have these "cosmopolitan" native executables that run on all platforms - would it be possible to link one copy of a large native library (ex: OpenCV or Intel MKL) and then not worry or think about platform specifics?
And how does this all play with GraalVM native compilation? Could I still compile a native executables after using this FFI?
Then you could go full circle and get a native exectable that's cosmopolitan ...
Afaik cosmopolitan is only meaningful for executable startups, the actual x86 binaries can be platform-agnostic, but only if they basically do no communication with the outside world (or very little), since otherwise they have to use OS APIs.
So, not sure that the same version can be linked, but most libraries have a shared API with platform-specific implementations and one can just link against them, pretty much how it is done today in e.g. Blender.
GraalVM is a bit trickier as it can be used to interpret LLVM bytecode, which will be portable across OSs, both when native compiled or when used on top of JVM. But if it uses Panama it would get the aforementioned limitations as it is basically just a wrapper over dynamically wrapping libs.
I almost wrote to the mailing list (for the first time) asking to better support nested lifetimes, and then they just drop a new API that does it so much better :D I honestly don’t know why I thought that such an experienced team didn’t think of this little detail!
Then it doesn't really matter whether annotations are used or not, or some more low-level linker API (like FFM went with). As a user you just call into the generated bindings.
That's the philosophy: the JDK provides the low-level capabilities, and jextract provides the 'civilization', i.e. a usability focused layer on top. One of the advantages is that the JDK doesn't compete with other existing solutions, and those existing solutions can benefit from the new linking runtime APIs as well.
178 comments
[ 0.22 ms ] story [ 221 ms ] threadSo the API assumes pointers can't be larger than 64 bit?
One of the things that jumped out to me about that changes, was that I assume that this will allow for unsafe pointer math. I suppose this is a low level api, but I thought that was an interesting choice.
Not many machines currently, but CHERI has 129-bit pointers (yes, 129), and there's already some work on for instance Rust to be able to work with that (see https://faultlore.com/blah/fix-rust-pointers/ and https://faultlore.com/blah/tower-of-weakenings/), and also on GCC and glibc (https://lwn.net/Articles/909265/), and it's not completely improbable that this becomes more common. Creating a brand-new API today which cannot handle pointers wider than 64 bits seems a bit short-sighted.
See this paper for details: https://www.cl.cam.ac.uk/research/security/ctsrd/pdfs/201904...
2^64 can address over 16 petabytes. I’m not sure when I’ll be working on that scale, but n by the time it happens, Java can introduce new data types like BigLong to handle it.
https://github.com/GavinRay97/panama-liburing/blob/6a80673e7...
You can see that a bit further down below when ".toRawLongValue()" is called:
Finally had somewhere to post this obscure project, haha
I thought a potential CPU of the future could have 128 bit "word size" for integer calculations and as a side effect also 128 bit pointers to reuse registers/instructions for both of them (just like today with 64 bit CPUs, indeed you don't need to map the entire address space but pointers are still 64 bit because it's the CPU's word size). And then address space layout randomization in a future OS could choose to map very high address ranges for the process, which can't be represented with Java's long.
[1] https://www.cl.cam.ac.uk/research/security/ctsrd/cheri/
Things have gotten exponentially larger in the meantime... with your average home computer going from < 1GB of RAM to 8GB and ever increasingly larger (my cell phone has 12GB of RAM and 512GB of storage for what it's worth).
Having storage ranging in the Terabyte category is simply the norm, and things like Petabytes of storage are rapidly becoming more accessible for average users.
Saying "X is enough" - ever - in computing is foolhardy.
This is not true, no one seriously thought 65 KB was ever going to be any sort of a limit. If you're talking about the Bill Gates quote, it's basically a myth that never happened or was taken WAY out of context. Bill Gates himself has given interview where he talks about the entire state of released and upcoming computers of that time and exactly what everyone thought was going to happen and what actually did happen.
Every time someone in tech has said "that number is large enough", the number gets surpassed in no time.
So while 64 bit memory addresses seems way more than ample today, it will not be forever. That was the point...
It truly is in so many cases. Not stupidity, but perhaps hubris. The same hubris that says nobody will need more than 64 bits today. Given time, 64 bits will fall waste to 128 bits and more.
The people who designed IPv4 truly thought the number of IP's would be more than enough forever. They literally had no concept that one day your average person would own multiple computing devices and require multiple IP's just to get through a normal day. They were very wrong, and found out in only a few year's time.
The only constant in tech is our assumptions today will be wrong tomorrow. Assuming "X" is big enough is foolhardy in just about every scenario.
Every year was another iteration of these limits being updated, no one ever thought any of these numbers were going to stay static. It took 1MB of memory just to have a 24 bit color frame buffer at NTSC resolution.
IP addresses were set at 4 billion when you could print out a list of known computers and put it in a binder and we still use it today.
This idea that people had a general lack of foresight was completely untrue. What people did with limitations like 3,510 transistors is astounding.
That said, I completely agree with your sentiment about "X is enough". What has changed in the last 20 years: When we double RAM/storage/network now, the increase is enormous. It does feel like GPUs are still in the insane growth period. Very soon they will be more powerful and have more on-board RAM than whole rest of the computer.
* As for photons, this estimate finds 4*10^84 photons since start of universe:
https://cosmosmagazine.com/science/physics/how-many-photons-...
Maybe we need to use 1024-bit types?
The size of memory is a power of two because the bits in a pointer have two possible values.
But why do you need the length of a pointer to also be a power of two? Are you addressing the bits in the pointer?
Indeed. The entanglement code will crawl without easy direct addressing of the bits. We wouldn't want the universe to run even slower, would we now? It would also make the development emulator impossible to run leading to even more bugs and missed deadlines.
The morale of the story is humans are insecure fragile little creatures, half of us are blind and the other half are pessimists because we can imagine what the truth/future looks like. Lies only last the time you can use energy to hide them.
Anyhow the arch of binary evolution is over; to build a MMU that can adress 64-bits of data is probably impossible with electrons. Just going from 64GB to 256GB is hard and makes things slower! Caches appeared in 1985, so since then the bottle neck has been RAM latency:
https://gettotext.com/largest-ram-bar-in-the-world-consumes-...
The biggest server from Oracle currently has 16 TB of RAM, good luck multiplying that by the difference in energy content per mass difference between oil and uranium (1.000.000x).
And good luck paying your energy bill. 64-bit RAM would consume 5120W * 1.000.000 = 5GW (you want 5x nuclear power plants with that server?)
Personally I'm staying on 32-bit for my ARMv8 cluster, my processes are limited to 4GB RAM each but since I only have 8GB of total RAM there is ZERO difference in switching to 64-bit as it effectively halves the RAM.
I made a comment about the virtual memory space of most desktop CPUs in use. I have no idea what you are talking about, did you mean to reply to me?
Anyhow the arch of binary evolution is over;
I don't think these words together mean anything.
to build a MMU that can adress 64-bits of data is probably impossible with electrons.
It's strange to call something impossible when it has already been done.
More likely: If 128-bit address space really takes off, they can create a new largest integral type long128 that is 16 bytes/128 bits, and either extend the existing MemorySegment, or create MemorySegmentLarge to allow for bizarrely large address spaces, like up to 1024-bit.
Another one that people like to pick on Java about: Arrays are limited to max size of 2^31-1 (non-negative part of a 32-bit signed int). To rephrase your question: <<So the API assumes arrays can't be larger than a 32 bit signed int?>> Yeah, I guess.
Point is, your reply is exactly right. Arrays can't be 64-bit large? Yeah, I guess.
I thought of something like IntPtr in C# (native size int). Although, to be portable, JVM would have to disallow doing pointer math on it, to make IntPtr fully opaque.
Plus Panama won’t go stable until Valhalla, which is necessary to actually have a “long long” in the language.
The JEP is really elegantly written!
From the link:
> Oracle's sales arbitrarily selects some feature versions for which to offer an LTS service, and other companies follow their choice
This does not seem to be strictly true. The release cadence is scheduled, with mostly predictable release times.[1][2]
The idea was, if some feature didn't make it's way into this release, it'll just get into the next release (which is only a few months away). Very similar to how the Linux Kernel does releases - arbitrary in features, but not arbitrary in time.
And while Oracle may retain a great deal of influence over the OpenJDK project, Oracle is not the OpenJDK project anymore. There are a lot of other voices to be heard that decide when and what is done.
> BTW, [other companies] can choose to offer LTS even for releases that have already been made and retroactively make them "LTS releases." There's absolutely nothing special about them
He's right about this. However, the reality is most companies offer the same LTS as was scheduled, with extra paid support for anyone willing to pay (and be stuck on) a regular release.
[1] https://www.java.com/releases/
[2] https://www.oracle.com/java/technologies/java-se-support-roa...
While there is surely (very welcome) other voices as well, I am not sure I can agree with this statement given that 95+% of OpenJDK development is done by people working for Oracle.
For _many_ enterprise users, there is indeed something particularly special about the LTS releases. Even if it's just a marketing term, it's still important to realize that organizations value stability, and the LTS releases can offer that at a different comfort level (and price point).
Yes, LTS was dreamed up as a way for Oracle to make money on open source Java. But the other non-Oracle vendors (equally important to the ecosystem) very much have similar offers of support that Oracle provides.
I'm glad for the model, frankly. And I'm excited about Java's future. LTS releases helps smooth out discussions with CTO types about how to live with Java. Developers can use the latest-greatest and be sure to target a particular LTS version for deployment. Finally Java seems to be moving again.
When pron comes in here and smacks us down with his replies, that's OK, I'm comfortable with my perspective. :)
And glad you are excited about the future of Java and the model itself! Most of this work is funded by the LTS model which was designed to give companies the flexibility to decide their upgrade strategy. Lots of teams want to move quickly and get new features, while others just want the app in the corner to be stable for years to come.
Unless your business is keen on upgrading the JDK every 1.5 quarters it’s simply easier to rely on LTS versions.
The LTS support guarantees are even true for non-Oracle JDK builds. For example, Amazon Coretto also follows the LTS cycle.
The last time I poked at it, there were just so many config and generated files and so much complexity that it felt like I must use an IDE that hides a layer of “magic”.
Or am I just confessing ignorance and this isn’t a thing and it’s no more complex and magical than Rust or JavaScript or Python?
Edit: thank you all for the helpful responses.
It's still a fairly verbose language, but it's miles from where it was 10 years ago.
I’m kind of excited now to try it again.
But to actually provide an answer, records shorten the language to a great degree in my opinion, there is also type inference with `var`, so on a local scope you can write really short code. The main method is still chatty, but it’s not like you actually have to write all that many times, plus it is just psvm for most IDE users.
...Although I will admit that whether its feasible or useful to demystify the magic varies from case to case.
As for Java, an IDE helps a lot for Java because the build landscape is quite tedious otherwise.
In terms of complexity, it really depends on what you want to do. Using a powerful framework like Spring can entail some config (albeit much less than it used to). Also you would typically use a build tool like maven or gradle to manage dependencies, build artifacts, etc.. Especially maven can be a little arcane. But another major upside of the aforementioned maturity is that there are reams of docs and stackoverflow answers which will almost certainly contain solutions for any problems you might encounter.
This is both a blessing and a curse. Some answers and docs are decades old and although still work, are not “fashionable java” (think streams, for instance).
Has that gotten better recently? It's been years since I've toyed with it.
A lot of cruft is still there; Date, File, InputStream/OutputStream, sun.misc.Unsafe, and the entire legacy reflection API are the bunch that stick out to me. Newer releases are actively mentioning their legacy status in documentation, and there are certainly JEPs to remove them or make them opt-in/opt-out.
If you look at OpenJDK internals, or even the foreign function/memory APIs as described in the article, it looks almost nothing like the Java I learned on and wrote for several years. Most of the Panama API is piggybacking on additions to the language made post-JDK9 or so, such as MethodHandle, VarHandle and @PolymorphicSignature methods. So I'd say the language and runtime is evolving nicely, even under the thumb of Oracle.
I think I missed the announcement of those being "legacy" APIs? They show up all over the place including in libraries, what is the replacement?
Did I miss something somewhere ? java.lang.reflect is still the standard way of doing Reflection.
This is it. There are things which are better in Java than in the other ecosystems you mentioned (e.g. dependency management) and there are things which are worse (the language is more chatty, maybe the designs tend to be more convoluted, but this differs project to project). Even enterprise Java has come a long way, it's different to what it has been a decade ago, it's definitely more lean.
Every sane developer uses either Jetbrains' product for JS, Python or Rust, or they use VS Code, which, after installing all plugins to reach the same productivity as with Jetbrains, becomes an IDE as well.
You seem to vastly overestimate the usage of IDEs with scripting languages. In my experience, the vast majority of developers working with scripting languages such as JavaScript, Python or Rust, still use plain text editors such as Vim or Sublime Text. They find these editors to be more convenient and faster than IDEs.
Even people who are on VS Code seem to be using only the built-in language support for scripting.
one of these, is not like the others :)
> They find these editors to be more convenient and faster than IDEs.
FWIW, survey responses from 2021 imply that 54% of Rust devs use VSCode, 28% use a vi variant and 21% use IntelliJ[1].
[1]: Page 19, https://raw.githubusercontent.com/rust-lang/surveys/main/sur...
Definitely not in my experience, most people I know use VSCode, which I wouldn't call a plain text editor (not necessarily an IDE either though). Most people will use the plugins for each language since those are auto-recommended when you open a new file in that language, such as Pylance for Python, and most people will click "install recommended plugins" and call it a day.
Vim users are few and far between in my experience, and Sublime Text even more so, most everyone has migrated to VSCode at this point that I know of.
https://lp.jetbrains.com/python-developers-survey-2021/#Deve...
State of JS doesn't seem to include the question any more, but it found in 2019 that about 70% used one of the two (mostly VSCode).
https://2019.stateofjs.com/other-tools/
VSCode may not be a full IDE without extra plugins enabled, but it's a far cry from a plain text editor.
And emacs users never had a plain text editor, never claimed as such, and woe be to you if you call it such in front of them. Lol.
But surely, for advent of code scripting you don’t need it, but neither does Java.
There are all kinds of things that you can pile on top of it, usually for managing big projects. Those can seem arduous when you're at the Hello World level. If you got introduced to those it will seem daunting and unnecessary (and for many projects, it is).
But basic Java is no more onerous than Python or JavaScript. About the only difference at that scale is that Java requires type notation, but no more so than C.
And I wrote Java for over a decade with vi. IDEs make it better, but they are not necessary. (And good ones are free anyway.)
And, yes, I agree 100% about your reference to low cost developers. From an enterprise view, it is cheap and easy to find (low quality and) low cost developers to maintain legacy Java software.
You also wrote: <<... static typing allows for deterministic refactoring of bad code. That's something you can't easily do in JavaScript.>> Most JavaScript devs would immediately reply: "Oh, use TypeScript for that." As I understand, you can incrementally upgrade a legacy JavaScript project to TypeScript, then slowly add types. Also, I have refactored lots of Java code that uses Object as a substitute for C's void*. That type of code is so difficult to understand without a debugger. Also, very difficult to refactor due to limited typing.
- Pattern matching
- Sealed types
- Records (immutable, succinct data-classes)
- Multiline strings
Among other things. It's almost as nice to use as Kotlin, and I say this as a huge Kotlin fan. Its pattern matching in most recent releases is actually more powerful than Kotlins, since it allows deconstruction-bindings in patterns.
Since Java's history is very focused on not breaking things (and folks got really grumpy on the few occasions something has been broken), Java cannot ever match the feature pace of languages like C# either.
But the folks writing Java code (most of you here on HN by all metrics), mostly don't care. They enjoy backwards compatibility and stability far more than new features. The overwhelming majority of newly written Java code is targeting Java8 still - which doesn't use any of these new features anyway.
Backwards compatibility is also why things like lambda's and streams are the way they are in Java (and most FP folks would sneer at), and things like Records took years to release (still technically in the Preview stage).
The advantage Kotlin has, and the reason it's growing in popularity in backend development is you get all the FP tasty features you want right now, but maintain near drop-in compatibility with existing Java libraries and frameworks. This was the most brilliant move by the Kotlin designers in my opinion...
What Kotlin features are possible because of that freedom ? Genetics can be an example I can’t say it’s impossible for Java to add in out refied keywords
That's by deliberate choice. They are going down the route of having the last mover advantage. Lots of people have complained about C#'s kitchen sink type of approach for example. And the more features you have, the more chance that they won't fit together neatly and cleanly.
A couple of examples that come to mind, Java's pattern matching/destructoring and upcoming string templates (JEP 430) are much more fully fledged compared to their Kotlin counterparts.
It also has the advantage of being the platform language. Now that we have virtual threads on the JVM, async/await immediately becomes irrelevant. However, Kotlin now has to maintain coroutines even though the platform offers a better way of doing things.
The amount of syntax I see literally 1:1 taken over by dozen other languages is really impressive and evidence for that.
A lot of its features for functional programming got swallowed up in later C# versions, and it's the Red-Headed Stepchild of the CLR (let's pretend VB.NET doesn't exist).
MS allows it to exist but it's a second-class citizen on the CLR, and, I think, always will be =(
And F# was created as a research project and is a lot more community driven than C#. So if Microsoft starts putting more people onto that, I think a part of that community will also scream that they should stay out.
I know those numbers, and can even refer to the blog post they were presented, if a big company like Microsoft wants people to use language XYZ, they can make it happen if management cares about it.
However they aren't caring enough to sort out the GUI civil war, so why would the .NET languages by any different, regarding coherent management across the board.
That would be the case for pretty much any language that has lots of features (provided that most of those features aren't completely terrible). A good design (at least for a mainstream language) also strives to minimise the number of features, not adding everything you can but only adding things you absolutely need. In the case of C#, many of its features are not widely adopted, and Java in particular will never adopt them.
Java's philosophy has always been to wrap an innovative runtime in a conservative language that only adds features late, after they've proven their worth elsewhere and when most mainstream programmers are ready for them, with the realisation that every added feature adds a cost to learning the language. That strategy has worked very well for Java, but .NET has a different strategy (a more adventurous language built on top of a less adventurous runtime). We'd rather spend two years thinking about how to avoid adding a new language feature than spend six months adding it. This "last-mover" strategy has helped us maintain our philosophy and keep the number of features small compared to C#. We strive to only add features that have a big bang-for-the buck and that, preferably, solve many problems at once, rather than add many features, each addressing a relatively small problem. For example, virtual threads have allowed us to avoid adopting async/await; records are allowing us to avoid adopting properties, and will likely help us avoid adding named and default parameters as a separate feature (which, in languages like C#, Swift, and Kotlin breaks binary compatibility/separate compilation).
Very cool. Is there any material available about this for further reading?
Thank God. Don’t get me wrong, C# is a cool language but languages suffocate under so many features, most devs will simply never ever learn most of them. And some of these features while invaluable in certain rare cases, I would rather prefer a better, more fundamental feature that takes more time and single-handedly solves for many situations.
Unfortunately modern languages really like to throw in everything they have seen from other languages ever, and even with very smart language designers these features will inevitably tangle (khm, swift).
CsWinRT and win32metadata are still quite far from a great usability experience.
I recently wrote a database buffer pool with it, allocating raw aligned memory and directly casting bytes from DB files into in-memory struct pointers.
It's very nearly a systems language in terms of capabilities.
Java 8 users are now a minority. Some libraries still target it (although Spring 6 targets 17 as the baseline), but most Java code is in applications.
> Java can never be Kotlin
Java doesn't want to be Kotlin because it aims at a much wider audience. Back in the nineties James Gosling laid out a strategy of an innovative runtime wrapped in a conservative language that only adds the most beneficial features, and only after they've been successfully tried in other languages, and this has worked very well.
Also, the Java language has the advantage of controlling the runtime, which allows us to add a smaller number of features, which are more powerful (e.g. compare records with data classes, or virtual threads with syntactic coroutines), while Kotlin can neither change the runtime nor have a significant impact on the ecosystem, and so is more limited in what it can achieve. Moreover, Kotlin's features are increasingly mismatches with the evolution of the platform.
Nevertheless, we are happy that the platform offers more feature rich languages to the minority of developers that do prefer them (or languages with radically different approaches, such as Clojure), so the platform can cater to programmers with different language preferences.
The last things missing are properties (which should be coming with reconstructors), and nullable types. For me, nullable types are not worth the switch.
All that being said, I don't think the languages are mutually exclusive. As a JVM developer you retain all your knowledge of the JVM and it's standard library. Lastly, a language doesn't have to be the dominate language on a platform to be usable and employable (just look at Scala).
I think the whole config/generated files thing is for old-school J2EE "enterprise Java". Most of the frameworks I've used have just involved writing code. Sure, sometimes you need a config file, but that's pretty normal -- most of the time I'd rather specify things like port numbers and logging configuration in a separate config file, rather than hard-code them in the app themselves. If you stay away from the old-school Java Servlet frameworks -- or use a framework that builds on top of servlets and hides the complexity -- then you don't have to deal with that crap.
The build ecosystem is a bit more fragmented than Rust (maven or gradle or sbt or...), and the build tools do require a bit more boilerplate to configure, for the most part (especially maven), but it's not too bad. JavaScript, IMO, has some of the most inscrutable build systems I've ever seen, so I don't think that's comparable to Rust, or even Java. Maybe the complexity of Java build systems is similar to Python, though in different ways.
The recent releases of Java have added a lot of quality-of-life improvements to the language, so it's a lot more pleasant (and less verbose) to write Java than it used to be. I still prefer something like Scala (2; haven't tried 3 yet), but it's a lot easier to build a team around Java than Scala.
I worked take a second look at IntelliJ and Eclipse; learn the keyboard shortcuts. Modern Java is incredibly well put together.
Most of the tooling is provided, and it's coherent and robust.
Ultimately - both Maven and Groovy, which are used for production level build and packaging, are a 'weird'. But getting going with them is relatively easy.
Java has introduced the concept of 'Modules' - which if you don't get straight in your head, can be confusing, but ultimately it's not that bad.
Compilation is relatively fast as well.
The 'IDE' tends to 'hide a lot of things' in ugly ways - that is true. All of the JAVA IDEs are weird about that. However - because Java is a well maintained language, the IDE's can be powerful and are actually worthwhile. Jetbrains being one of them.
Sadly, Java on VSCode is a bit of a mess.
On Android, Google has introduced a bunch of odd conventions and complexities which I feel are unnecessary.
If anything I’d say JS has a more complex configuration story than Java.
https://www.jbang.dev/
I'll take that a a major plus. Sometimes things are improved by what is taken away.
> I don't see any real use of Java in 2022 and beyond.
Well, you see what you see; and the cloud infrastructures sees what it sees.
Also, sprint is not slow at all, especially that servers are very famously IO-heavy. Nonetheless, you can expect better performance for these with project loom.
---
One of the coolest things that's been worked on (by this same author, no less!) isn't even in the article!
Per has written a pretty-printer for MemorySegments and ByteBuffers that can hex-dump memory or render memory/buffers as their "struct" representations given some MemoryLayout.
You can also customize it with your own printers, it's wicked cool and helps so much to debug buffers when working with them.
https://github.com/openjdk/panama-foreign/pull/695
What do I mean by that? Have a look at this comment for an image of a raw memory structure layout I represented with MemoryLayout, and the pretty-print rendering of it:
https://github.com/openjdk/panama-foreign/pull/695#issuecomm...
It looks like something I'd expect to either be an external tool (like VisualVM) or part of an IDE
Except when they use @Autowired. (Ackshually aside, I do agree with the sentiment of your post. The standard library is arguably one of Java's greatest assets)
When I saw your top-level comment, I must have mixed up your name with a different Gavin [1] until a quick Google search fixed the mix up :)
1: Gavin King of Hibernate fame.
Sorry for the tangent, it had to get out somewhere and I did not think it was worthy of an email in the actual review thread : - )
``` var segment = MemorySegment.ofAddress(somePointer, sizeofStruct, memorySession); segment.set(ValueLayout.JAVA_LONG, offset, value) ```
Appreciate the example. Thank you.
Of course you are not required to do FFI, you may want to use this API to speed up some very memory-sensitive operation. Then you can define your own memory layout, specifying precisely endianness, alignment, padding, anything, and access it comfortably through these APIs.
Do you happen to know if the `get` causes allocation in the Java side there?
0: https://openjdk.org/projects/panama/
But it is certainly a much better way to interact with native APIs.
It's similar to the original Calendar API (as old as Java 1.1) versus the new Date/Time API introduced in Java 8.
And how does this all play with GraalVM native compilation? Could I still compile a native executables after using this FFI?
Then you could go full circle and get a native exectable that's cosmopolitan ...
So, not sure that the same version can be linked, but most libraries have a shared API with platform-specific implementations and one can just link against them, pretty much how it is done today in e.g. Blender.
GraalVM is a bit trickier as it can be used to interpret LLVM bytecode, which will be portable across OSs, both when native compiled or when used on top of JVM. But if it uses Panama it would get the aforementioned limitations as it is basically just a wrapper over dynamically wrapping libs.
As always, thanks for the work!
There's also a tool that can generate all the bindings from a C header file automatically: https://github.com/openjdk/jextract
Then it doesn't really matter whether annotations are used or not, or some more low-level linker API (like FFM went with). As a user you just call into the generated bindings.
That's the philosophy: the JDK provides the low-level capabilities, and jextract provides the 'civilization', i.e. a usability focused layer on top. One of the advantages is that the JDK doesn't compete with other existing solutions, and those existing solutions can benefit from the new linking runtime APIs as well.