18 ms·
Project Valhalla, Explained: How a Decade of Work Arrives in JDK 28
- theanonymousone 4mo agoDupe? https://news.ycombinator.com/item?id=48590056 https://news.ycombinator.com/item?id=48590056
- orphea 4mo ago1 comment Probably not.
- DarkNova6 4mo agoYou could probably a whole tech thriller on the evolution on Value Types in Java. I’ve been reading the mailing lists and watched all videos on the topic and it is truly inspiring how much they managed to consolidate the design to something that always looked like java. But while also going far deeper in granularity and understanding what it even means to be a value type and what optimizations can be done where
- joe_mwangi 4mo agoAnd the only syntax change is adding 'value'.
- rf15 4mo agoI appreciate the hard work that went into the things that did make it into Valhalla eventually, but: > The model was powerful, but also mentally heavy No it isn't! it is this interpretation that kills off the null-safety debate entirely. Saying you have a variable that cannot be null is not a mentally taxing distinction, especially since everything is labelled thoroughly. > The team, faithful to the lesson “simplify the model for the user, even at the cost of the performance ceiling,” ultimately dismantled this dualism. but it would have simplified it for the user. The whole attitude and process around this and the other topics gives me very little faith that Java can be steered in a sensible direction here. The type system of a programming language is supposed to give convenient guarantees to the developer on a CPU that can only do numbers. There is no reason to reduce the optional(!) safety guarantees you can offer with the excuse of "too mentally taxing". Hell, they even get there half way by recognising: > the language model and the JVM model don’t have to overlap one hundred percent
- andyjohnson0 4mo ago> The whole attitude and process around this and the other topics gives me very little faith that Java can be steered in a sensible direction here. I agree. The stewardship of Java seems rather lacking - particularly when compared to that of .net, where MS etc. mostly seemed to make the correct decisions from the start. Does Java even have any value or mindshare at Oracle nowadays? The company seems to be a datacentre/compute business at this point, with appendiges for its legacy activities and a vast overhang of debt. I sometimes wonder if the only parts of Oracle that are still profitable are the Legal and Lawnmower divisions.
- rf15 4mo agoHow .net got so many things right where java did not is a mystery to me, but appreciated (it has its own flaws, of course). Java, in my understanding, is still of core relevance to Oracle, and tied into a lot of contracts that require very little effort from them to maintain. But you are correct in observing that they want to be a datacentre/compute business more and more these days; they may have in fact overcomitted to this due to the AI craze, since shareholders are already complaining.
- torginus 4mo agoI know its a faux pas in the Java world to acknowledge the existence of .NET, but how does this differ from .NET structs? Value types, generic specialization, boxing - a quick skim makes it looks like they picked the same choices.
- rf15 4mo agoFunctionally they don't - java is just catching up with (by now) ancient practice. The false dichotomy of > A struct in C# has identity and mutation, so the semantics of copying on assignment or passing have to be precisely defined, which gives a heavier model for the programmer and less freedom for the runtime. Doesn't really match with what they're describing. While yes, it will not have identity in a java class ref sense, it of course will still have identity in being a unique structure in memory at a certain address. This is just splitting hairs about Java nomenclature.
- torginus 4mo agoI don't wanna badmouth Java people, but how they push the idea that this thing is some sort of genuine breakthrough that took multiple PhDs years of cutting-edge research to implement, when in fact they basically copied what .NET did from basically year 1, is not a good look. Again, not trying to turn this into a .NET vs Java thing, I'd have been much happier if they reached some new and interesting conclusions.
- misja111 4mo agoThis is exactly what made it so difficult. It is much easier to have a feature like this from year 1 than to add it to a language that has grown and evolved for 18 years already.
- rf15 4mo agoI agree with this sentiment. The work they put in deserves a lot of respect, and took a lot of effort, no doubt. It's just the framing they push to the public that could use some work.
- evdubs 4mo ago[flagged]
- geokon 4mo agoa few questions for the pros > "The defining trait: no identity" I get that this makes objects behave like primitive types. Maybe thats reason enough. But is it necessary for the performance boost and de-fluffing the objects? Seems like an orthogonal objective > There’s a catch worth knowing about here, though: flattened data has to be readable and writable atomically (otherwise it risks “tearing” under concurrent access). Isn't this a race condition and "undefined bahvior"..? Having to limit yourself to atomic sizes seems like a huge limitation, to accomodate what is most likely buggy code. Is all the effort only gunna help lil toy ColorRGB examples? > The points array is a million pointers. Each pointer leads to a separate Point object lying somewhere on the heap. Does this happen in actuality? One would assume the allocator tries to put stuff sequentially on the heap? Its not a guarantee as with these Value Types, but I'd think you could get similar-ish perf with prefetching in cache. I dunno whats happening under the hood.. But when writing Clojure apps the JVM always reserves absurd amounts of heapspace on my machine (to my annoyance). Id assume it can find some place to do contiguous allocations.. Which i guess gets me to my last question... where are the benchmarks broski? It all sounds great, but does it actually yield the insane speedups promised? Great article, well written. But a benchmark would have been a nice "punchline"
- rf15 4mo ago> I get that this makes objects behave like primitive types. Maybe thats reason enough. But is it necessary for the performance boost and de-fluffing the objects? Seems like an orthogonal objective It feels like an orthogonal objective and honestly arbitrary distinction, yes. > Isn't this a race condition and "undefined bahvior"..? Having to limit yourself to atomic sizes seems like a huge limitation, to accomodate what is most likely buggy code. I think they meant it like the appearance of atomic behavior from a java multithreading view. > Does this happen in actuality? Yes, it does happen. Having guarantees on this front leads to better performance. > But when writing Clojure apps the JVM always reserves absurd amounts of heapspace on my machine (to my annoyance) Might be a configuration problem?
- gf000 4mo ago> Is all the effort only gunna help lil toy ColorRGB examples Arguably flattening mostly makes sense for these only. And yeah, you are right that allocations happen on something called a thread local allocation buffer, which is basically just a pointer bump in cost and objects allocated one after the other should be physically close in memory for the most part (though an object's creation may require a bunch of other object's creation that would sit in-between). But these have headers, so not as dense as they could be (though due to GCs being generational, they may end up actually closer in the next gen? The in-between temporary objects wouldn't survive for the most part)
- layer8 4mo ago> But careful: == looks at internal state, which isn’t always what the object represents, so for “is this the same data” comparisons keep using equals. So == for value classes will basically be like memcmp(). That is a bit unfortunate, as it breaks encapsulation, exposing implementation details. Client code can use this to do case distinctions based on how a given value is internally represented. In a way, it’s worse than identity comparison, because identity comparison at least doesn’t expose internal state.
- ahartmetz 4mo agoIf your bags of data have internal state, there's something wrong with your bags of data. I assume that the Java guys thought far enough to either exclude padding from comparisons or force padding bytes to be zero. It should work even for strings: They will surely continue to be heap-allocated, and memcmp-ing pointers (inside the new "structs") is exactly an identity comparison.
- layer8 4mo agoThere’s nothing wrong with having non-normalized representations, that’s why there is equals(). For example, you might have a value class for representing (limited-precision) fractions using two longs internally, for the numerator and denominator. For efficiency trade-off reasons, you don’t want to always shorten the fraction. But now client code can distinguish 2/3 from 4/6 using ==. Scenarios of that sort are conceivable where this actually leaks sensitive information. In any case, it creates dependencies on implementation details where you don’t want to have them. When designing a value class, you are now in the dilemma of either always having to normalize the representation, costing performance, or having your class be a funnel for leaking implementation details.
- ahartmetz 4mo agoWell. I'd be upset if custom operator==() for plain-old-data structs was removed from C++, but Java never had it to begin with, so for Java, it just means that you have to fall back to using traditional classes (or compare using something other than ==) if you need such "fancy" features.
- orthoxerox 4mo ago> Will I get a fast, flat `ArrayList<Point>`? Not yet. Sad. Hope they can do this by the next LTS JDK.
- piokoch 4mo agoYup. That's a big disappointment they could not cram universal generics faster. But I get the problem - they have to preserve backwards compatibility. I can take 30 y.o. Java 1.0 JAR and run it on Java 27 and it will work.
- tsimionescu 4mo agoAs I understand it, this is anyway an extremely limited perf enhancement - for any class whose data size isn't guaranteed to be atomically writable on your CPU, after including the nullability overhead, it doesn't do anything, basically. On a CPU where 64 bits is the max guaranteed atomic read/write, even Point[] will not get optimized, since you need at least 65 bits of memory for a point value (since it has two 32 bit int fields, and it needs an extra bit to specify if it's null or not - so in practice it will take up 72 bits at the very least, possibly more with alignment requirements). But even after fixing this, if you have 3D points or if you need 64bit coordinates, your value type 3DPoints will still be individually heap allocated and your 3DPoint[] will store pointers to them, just like today, on most processors. Given that the JVM could already do escape analysis and allocate regular classes on the stack in certain scenarios, it's very unclear what benefit, if any, this will bring for normal processors for anything except the base wrapper types - even after implementing generic support and nullability for value types in a future JVM.
- lowbloodsugar 4mo agoWhich is why this is the wrong approach. Again. This is a major misstep.
- boroboro4 4mo agoThe core insight there is to separate value semantics (no identity) from reference (itself) semantics (nullability). While this particular change can bring very limited amount of improvements it’s still does some - probably smaller to no object header + more guaranteed optimizations for variables on stack. It’s when they land next part (nullability) it will shine fully - particularly on the intersection of not null and value. Alternatively if they introduce tearable semantics it will also shine - it would be possible to still optimize array of value classes, even if they are nullable (for example by having correspondent nullability mask). So they are taking right step in a right direction. They are just trying to land this incrementally.
- ahartmetz 4mo agoFrom the article: > In 1995, a memory access cost roughly the same as a CPU operation Uhm... no?! Here's a CS paper from 1993(!) about prefetching from cache(!!) because the cache was slower than the ALU. https://www.eecs.umich.edu/techreports/cse/93/CSE-TR-152-93.pdf https://www.eecs.umich.edu/techreports/cse/93/CSE-TR-152-93.... It would perhaps make Java look a little bad to say that, in 1995, the prevailing attitude in certain circles was "If it's too slow, just wait for faster hardware - Moore's Law forever baby!" (Of course, Sun was selling, at the time, relatively fast hardware - the slower the software, the faster the required hardware)
- Athas 4mo agoYes, this also stood out to me. I usually think of CPUs and memory having parity in the early 80s, but I never bothered to check for sure. I do remember some early computer architects writing about memory being faster than the CPU!
- ahartmetz 4mo agoEarly 80s is also what I remember, mainly from articles about old CPUs on HN - like the zero page on the 6502 that served as a sort of L2 register file.
- dboreham 4mo agoWell, yes but no: The Z80 took 3 cycles to load from memory. A register to register transfer took 4 cycles (including fetching the instruction). Only one of those cycles was instruction execution. I think the only reasonably mainstream scenario where the CPU would be significantly slower than memory would be the serial CPU designs such as the PDP-8/s. That said, at the time people were doing cool stuff with 8-bit CPUs, they weren't running software remotely like what we're discussing here. That would have been done on a VAX, which had instruction and data caches. What really happened, that the article is alluding to is that memory didn't get much faster in absolute terms since the 1980s. CPUs on the other hand did. E.g. in the 1980s we had 60ns DRAM. Today DDR5 I believe allows about 10ns random access reads best case (6X). Over the same period CPU clock speeds have increased from about 8MHz to 5GHz (600X).
- tomaytotomato 4mo agoA lot of the comments on here are a bit unfair on what is great work being done and even more awesome work (JEPs) in the pipeline for the future. If Java was a child, imagine it being brought up by loving parents for the first few years (Sun) then it was thrown in a garage with some other children and neglected by its evil guardian (Oracle) Neglected and unloved till JDK 8, its basically been playing catch up. So when people say "oh so its now got structs or value types of X", yes it has but that's because it has been stunted in its development due to big bureaucratic and hostile corporate processes, but its free now and is getting love through the OpenJDK family. I will continue to enjoy writing once and deploying anywhere!
- gf000 4mo ago> If Java was a child, imagine it being brought up by loving parents for the first few years (Sun) then it was thrown in a garage with some other children and neglected by its evil guardian (Oracle) Whether you like oracle or not, this is simply not a correct description of Java's history. It was brought up by loving parents, who due to financial problems had to put Java into a foster home where she was neglected. But later it was adopted by new, loving parents (Oracle) and she bloomed and become a healthy and stable adult. Like, it was Oracle that completed the open-sourcing of the platform, making OpenJDK the reference implementation. They also open-sourced the previously proprietary jfr, mission control etc tools. They also managed to keep many of the original members of the language team, which is quite rare during these acquisitions, and Java has seen a huge improvement both on the language and runtime front.
- cogman10 4mo agoYup. I was around for and skeptical of the Oracle purchase of Sun. I was worried about what it would mean for Java. The Java team has been delivering nice language and environment improvements regularly since Java 10.
- bdamm 4mo agoWell, Oracle may have done fine, but IIRC open sourcing the JDK was Sun's very penultimate move on its deathbed. Oracle inherited the license to the trademark, but the actual JDK was already free.
- Alexander-Barth 4mo agoI think this is quite similar to julia's handling of a struct. An array of mutable structs is just an array of pointers, where every pointer directs to the underlying structure. However with an array of structs (immutable is the default), there is no such indirection. The value of all fields are stored as array element (unless you have an array of heterogeneous elements). If you want to change an element of such an array you need to create a new immutable struct which in practice it is quite fast, but a bit verbose to write.
- aykutseker 4mo agoI think a lot of people will file this under Java got structs. That seems off. They're still objects, the new thing is that they can give up identity.
- rom1v 4mo ago> The difference in the code is exactly one word: value. What is unclear to me is why the decision to use a Point instance as a value or as a reference is made in the class definition rather than by the caller. > Point[] point = new Point[10]; For the same class, I might need an array of values in one place and an array of references elsewhere within the same codebase.
- tikotus 4mo agoWhat about the case of just needing one, not a collection? And when a function receives a Point, how does it know if it's a value or a reference?
- jayd16 4mo agoIt would really break the GC or the type system if you did that. If you return a single point out of a 100k long array, it has to pin the array? How do you track the GC root? Struct array elements need back pointers? Conversely, if it auto-copies now you have to contend with runtime state changing the pass semantics?
- leiroigh 4mo agoI'll be interested in seeing the fallout of the (unavoidable) compat issue: If I have a function that has a value `x` that erases to `java.lang.Object` (e.g. a parametric function with no lower bound); then it used to be safe to check for nullity and then synchronize on the object. This is no longer safe: This can now throw `IdentityException` into your face. (it was _never_ a good idea) In other words, a lot of old code must be reviewed. I suspect that `-XX:DiagnoseSyncOnValueBasedClasses=2` will need to stay (with the semantics: if user tries to synchronize on identity-less object, then log a JFR event and make it a NOP, don't throw an exception)! The current JEP text is a little too ambiguous to figure out whether that is the plan, anyways.
- watt 4mo agoYou lost me at "I have a function that has a value `x`". How does function "have" a value?
- porridgeraisin 4mo agoI think they meant function that takes a value x as an argument.
- pregnenolone 4mo agoLooking into the negative comments is quite amusing. Not only do most of them contain technical inaccuracies, but of course, they also need to mention how great .NET supposedly has been from the beginning and how Java supposedly copied everything. Let's take a stroll down memory lane. First of all, .NET literally started as a Java copy. On top of it, a non-cross-platform one for almost two decades! After having shamed Linux for so long Microsoft finally started porting .NET to other platforms in a non-backward compatible way. A lot of .NET proponents will tell you porting from legacy .NET to .NET Core (which was renamed once again to .NET) would be a quick fix, but it isn't. For example, the shop I used to work in had some important cryptographic libraries which were very painful to port. And then, there's .NET's simplistic garbage collector, which can be quite annoying because it tries to be a one-fit-all solution that basically cannot be tweaked at all, often resulting in unresolvable latency problems. There’s a lot of other stuff, like its ghetto-like ecosystem and the insane fragmentation of GUI libraries. I also don't get the C# praise. Over the years, it has become quite the bloated language. It feels like Microsoft tries to implement every feature possible without realizing that an enterprise language is supposed to be streamlined. Async/await? Very ugly, very annoying. Java has solved this a lot better with virtual threads and structured concurrency. I could go on, but these "language wars" are silly and pointless. Both platforms have their pros and cons. Besides, I have a lot of bad things to say about the JVM as well, but it's nice to see Valhalla finally beocming reality. Too late for me personally though.
- ozim 4mo agoI like how you point out inaccuracies and next paragraph you deliver couple more, finishing with “language wars are silly and pointless”.
- pregnenolone 4mo ago> inaccuracies Like what?
- ozim 4mo agolegacy .NET to .NET Core (which was renamed once again to .NET) It was always .NET, only that new one had 1 till 4 had additional "Core" to clarify any confusion that could come from having same numbers as old. here's .NET's simplistic garbage collector ... it tries to be a one-fit-all solution that basically cannot be tweaked at all Definitely tweaking GC is not a thing in .NET land but it is far from "cannot be tweaked at all".
- nasso_dev 4mo agostopped reading when i saw the AI illustration. wholly unnecessary, and it feels insulting to be fed slop like this... if you really want a fun drawing get a human artist to do it. it doesn't need to be complicated, for example https://www.code-cartoons.com/ https://www.code-cartoons.com/ is mostly just stick figures and does an excellent job but you don't even need any of that, a mermaid diagram would have worked perfectly fine too. instead you chose to use a technology that is known to be harmful
- piiritaja 4mo agoThank you, no idea how this stuff gets upvoted here. The whole article reads like something Claude came up with.
- jeroenhd 4mo agoI simply do not trust articles that use slop imagery like this. I assume the text of this article (and realistically, most articles posted here) is also slop, but it's often difficult to tell. If you don't have the time or put in the effort to make your article, I'm not going to spend time and effort reading it. You really don't need some generic cartoon guy hovering over your graphs, draw them in MS paint or something.
- spbaar 4mo agoI have such an urge to comment "lgtm" on the 197k line change PR
- arein3 4mo agoDo it
- jeandrek 4mo agoAnyone know why the article's 4th picture is about the Jobs obituary gaffe? (It's not just for me, right?)
- Wilduck 4mo agoIt's because the author is comparing that incident to how they were prepared with the bulk of their analysis in advance. Ready to publish as soon as it happened.
- Hendrikto 4mo ago> The pull request alone adds over 197 thousand lines of code across 1,816 files. And that across 2819 commits. Wow, that’s insane.
- smallnix 4mo ago> [IMAGE: the same Point[] array in two variants: “before” (an array of arrows → scattered boxes with headers) and “after” (a uniform strip of number pairs)] The `Point[]` in the image tag of your LLM output crashed your image generation post processing.
- maelito 4mo agoWhat I have in mind when I read Valhalla : https://valhalla.openstreetmap.de/ https://valhalla.openstreetmap.de/
- jessinra98 4mo agoThe article has a section about that. For me, a struct in C/C# can be modified and is passed by copy while a value class can not be modified and is passed by value. I do not think you can do stack allocation in Java.
- joe_mwangi 4mo agoYup. By design, value classes will use cpu registers as a 1st priority instead.
- fsuts 4mo agoJava = Oracle = Ellisons way of doing business Unless your company forces you to use Java for new projects, consider a change
- recursive-call 4mo agoname another statically typed, compiled, mature language with a bunch of packages for everything and maybe I will /srs
- GHanku 4mo ago[dead]
- fsuts 4mo agoRust
- abbeyj 4mo agoThe one that immediately springs to mind is C#. Of all the mainstream languages it is probably the one most similar to Java. It can be compiled into platform-independent bytecode (like Java) or into native code using Native AOT. Relevant to the subject of this article, it has had support for structs (user-defined value types) since C# 1.0 in 2002.
- deleted 4mo ago[deleted]
- LelouBil 4mo agoI'm wondering what this means for Kotlin now
- drzaiusx11 4mo agoAm I understanding this correctly: a value type really only works when it fits on a 64 bit "cache line", and when larger, it falls back to normal heap allocated objects as before? Seems extremely limiting, no? Great for a boxing optimization, but not much else unless you're deal with very small data types regularly...
- mattstir 4mo agoThat's true for arrays of these value classes. Scalarization would help for larger local values though, since those would avoid pointer indirection for purely local values.
- lowbloodsugar 4mo agoAnd one bit for null! So “smaller data types” means 32bits! Yay! It’s 1995 again!
- logicchains 4mo agoSurely it can't be that, it destroys basically the entire value proposition of value types, unless you use a preprocessor to write everything as SOA.
- exidex 4mo agoLarger types are supported, there is A notion of tearing. According to JVM spec even long and double could tear, not sure about practical implications though
- vlovich123 4mo ago> Before we pop the champagne, though: this is preview, disabled by default, and, as Brian Goetz was quick to cool everyone down, “only the first part of Valhalla.” Goetz added a great observation that the “they’ll never ship it” crowd will now smoothly switch over to “but they didn’t ship the most important part” (and a joke has been going around the community for years that we’ll sooner end up in Valhalla ourselves, the Norse-afterlife one, than the project ships). I don’t know if this is fair way to try to disarm your critics. The only thing that’s remained after this decade is the slogan so it’s a real ship of Theseus question if Valhalla has shipped since what’s delivered doesn’t achieve it. Congrats on the accomplishment, but from looking at what ended up, I’m not sure it’s a huge improvement. > The trouble is that this optimization is unpredictable and fragile. Is this describing escape analysis or value classes? Because the list of exclusions where this does anything is so large and the conversion to a heap type under the hood is so transparent and opaque, I think it can describe this technique as well. Also, the whole “works like an int” motto is violated - int is never null, int-> integer boxing is explicit and well understood. > In the new model, the wrapper classes themselves become value classes (when preview is on, Integer, Long, Double, and company lose their identity Oh neat, they sidestep that by changing the definition of an int. I’m sure it’ll be trivial to turn this on in the wild on code that may be relying on identity for boxed numerics. I think this alone shows this project can’t ever be turned on by default and now we’ll have a decade of two Java languages (one with value types and one without) as they try to convince everyone to migrate and then just turn it on (ie python3). So much opportunity squandered and dismissing critics as always having something to complain about is a neat way to sidestep legitimate criticism that this approach is not going to work out for Java.
- greekrich92 4mo agoGreat write-up. Java is getting so good. The improvements over the last decade have been unbelievable. The negativity here is bizarre. Just a reflex I suppose.
- MagicMoonlight 4mo ago[dead]
- joe_mwangi 4mo agoAnd I notice, people aren't aware more things are being planned for. For example, the carrier classes being proposed, they will separate state description with state representation and this is where value classes will shine syntactically.
- vanyaland 4mo ago[dead]
- mattstir 4mo ago> But the difference in memory is fundamental. The JVM can now store the values themselves in the array, laid out densely one after another: 8 bytes per point (plus a possible null flag), in a contiguous block. No headers per element. No pointers. No jumping around the heap. How much was this article proof-read? Didn't they just get finished talking about how heap flattening won't work for objects with > 64-bit representations? Their `Point` is at least 65 bits (two 32-bit ints plus the null flag). The "plus a possible null flag" and oddly short following statements seem to suggest this was some AI that got sidetracked by trying to make emphatic statements... oh and also the "[IMAGE: the same Point[] array in two variants..." block halfway down the page is unfortunate.
- dlopes7 4mo agoThe obviously used too much AI, I stopped after 2 paragraphs
- tzs 4mo agoThe first two paragraphs are > On June 15, Oracle engineer Lois Foltan confirmed what a good chunk of the industry had stopped believing: JEP 401: Value Classes and Objects will be integrated into the main OpenJDK repository and is targeting JDK 28. > The change is so large that the remaining committers were asked to hold off on bigger commits during the integration. The pull request alone adds over 197 thousand lines of code across 1,816 files. What in those paragraphs is obviously AI?
- yubblegum 4mo agoThese days I'm having second thoughts about pictures that I am pretty certain can't be AI but just have that look. It's strange but I've noticed it happening more and more.
- Raphael_Amiard 4mo agoI mean I’m only answering that because you’re asking, nothing set me off personally there, but now that you ask: « The pull request alone adds over 197 thousand lines of code across 1,816 files. » I noticed that both Claude and GPT are fond of those kind of stupid accounting statements that don’t mean a lot in and of themselves, but look impressive in a « wow numbers » way. Which is kind of ironic since counting remains one of their weak points
- minitech 4mo ago> How is this different from struct in C#? A struct in C# has identity Since when? I’m pretty sure structs didn’t have identity last time I used C#, and that would be a very surprising thing to add.
- FrustratedMonky 4mo agoSo, is this going to allow an F# like language to run on the JVM?
- vips7L 4mo agoWe’ve had Scala for years.
- exabrial 4mo agoTons of armchair critics but dang this is freaking cool!!! Thanks everyone for working on this an THANK YOU for moving slow and getting the design right!
- DarkmSparks 4mo agoWhy remove identity from Double and Integer? This is going to break so much stuff for no reason when double and int were already a thing.
- GYLQ 4mo agoThe gap between demo and production is always bigger than it looks. Things that work great on the examples in the README tend to fall apart on edge cases that aren't covered. Worth running it against your actual data before committing to it.
- nu11ptr 4mo agoI'm a little unclear as to when and under what conditions this results in non-heap objects, now (<= 64-bits?) and in the future (???). I thought that was the _ENTIRE_ point of this project, so I was surprised to see they can be null (did that change from before?). If it is always and forever limited to 64-bits, I fail to see the point of this entire project, as it would have been far simpler to add syntactic sugar (simply pass primitives underneath the covers) as Scala did to create value types vs. JVM changes.
- newsoftheday 4mo agoI just got my projects up to JDK 21 a few months ago. Working on trying to get one upgraded to JDK 25 now and now they're talking about delivering JDK 28 in less than a year from now. How are you supposed to keep up with these rapid updates?
- cogman10 4mo agoWhat did you go from to get to 21? Mostly just hit the LTSes is what we've been doing and since about 17 it's been a pretty easy process in general. Protip: If you ditch lombok everything gets a lot easier.
- bpodgursky 4mo agoHow much stuff actually broke? I feel like you can treat Java upgrades as minor upgrades most of the time, maybe you have to rebuild a few binaries but I'd be shocked if it required significant code changes.
- jeroenhd 4mo agoJDK 21 is a few years old now, so you were a few years behind. JDK 25 was released last year, which makes for the next stable LTS for a while. JDK 28 is expected in 2028, and these features are not going to be enabled by default for years after that. Java is generally backwards compatible, so unless you're using fat frameworks that use shady internals or known-deprecated APIs, you should generally be fine immediately upgrading to the latest LTS, possibly even non-LTS versions if you have confidence in your stack.
- cogman10 4mo ago> There’s a catch worth knowing about here, though: flattened data has to be readable and writable atomically (otherwise it risks “tearing” under concurrent access). I really hope they give an escape hatch for this. It will make it really hard to extract a lot of the benefit of valhala if you can't make a thread unsafe value class. It's also one of those problems that will be quite hard to run into. You basically need something like this class Bar { static Foo value[] = new Foo[10]; static void setFooFromManyThreads(Foo foo) { value[0] = foo; } value record Foo(int x, int y, int z) {}; } Not something you typically run into and generally already a thread safety problem. The solution is also simple, a `synchronized{}` block will fix it if you need to have a tearable class that's written from multiple threads. But the other thing is that for SIMD operations, you really need flattening, and that really does typically mean having something like `Foo(double x, double y, double z)` in play. It'd be a shame if the way we have to do this is a struct of arrays.
- geokon 4mo agoI actually don't understand the tearing they're talking about. If the fields are final then you can't modify the Value Type anyway? And a simple write-lock bit for fat Value Types would solve everything while maintaining most of the performance benefits (both on read and write)
- mandarax8 4mo ago> I actually don't understand the tearing they're talking about. If the fields are final then you can't modify the Value Type anyway? You can assign the object again to overwrite it 'in place'. > And a simple write-lock bit for fat Value Types would solve everything while maintaining most of the performance benefits (both on read and write) They even already have an extra 'null' bit tacked on to the value object.
- cogman10 4mo agoThe problem is concurrent access. A write bit on the value doesn't really help as you have to check and update the bit using atomic instructions. But you'd also need to reserve that bit for every read as concurrent access wouldn't be safe. That's the tearing problem. It gets worse because things you can't generally do in the JVM can happen. For example, if your value class contains a reference to an object but that reference just so happens to split a tear, it's possible one thread to see an invalid reference while another thread is writing that object. That could be fixed with some added padding based on the architecture to make sure stored references aren't tearable.
- narag 4mo agoI found a solution for what seems to be the same problem, in a different language: a particular type of lists, where the class metadata is stored once and the data for each instance is contiguously stored in a flat array. Not sure if it covers exactly the same terrain, but perusing the article, it seems to be the case, with a single instance being the degenerate case.
- cogman10 4mo agoYup, it's the same terrain. I've made something like this in the past. And I did it exactly because `List<Foo>` was too expensive and slow. class FooSOA extends Collection<Foo> { double x[]; double y[]; double z[]; Foo get(int index) { return new Foo(index); } record Foo(int index) { double x() { return FooSOA.this.x[i]; } double y() { return FooSOA.this.y[i]; } double z() { return FooSOA.this.z[i]; } } }
- dllrr 4mo agoAnd here I thought engineers were mostly logical and objective. This thread is very entertaining.
- azzzxcc123 4mo ago[dead]
- azzzxcc123 4mo ago[dead]
- lowbloodsugar 4mo ago“plus a null flag” is going to be the GIL of the JVM.
- gib444 4mo agoIt's slop o'clock
- mwkaufma 4mo agoFootnote 6 "How is this different from struct in C#" is inaccurate. Since the article is littered with AI-generated images, I assume the writing, or at least the research, is littered with hallucinations?
- juancn 4mo agoIt's still too unpredictable trying to be transparent IMHO. Scalarization can fail in surprising ways just due to what a maximal atomic write can be on the target platform, and then it fall back to heap allocated objects. Even if there's type erasure. I much rather have the compiler balk at me than let me write something that may or may not work as expected.
- w10-1 4mo agoA bit fuzzy and dramatic; luckily the original documents are quite readable: top-level page: https://openjdk.org/projects/jdk/28/spec/ https://openjdk.org/projects/jdk/28/spec/ JEP status: https://bugs.openjdk.org/secure/Dashboard.jspa?selectPageId=25101 https://bugs.openjdk.org/secure/Dashboard.jspa?selectPageId=... I'd really like to see someone trace related developments in C#, Swift, Java, and Rust, since they all have been racing to catch up to hardware, and I believe they are cross-pollinating. (My concern is how all this will affect the FFI memory shares.)
- slavapestov 4mo agoFWIW both Swift and Rust have had value types and generics that abstract over unboxed values since the start.
- gf000 4mo agoNot sure I would call them the same - not too familiar with Swift but for rust you probably mean types implementing the Copy trait? But Java's value types are a higher level semantic feature, these objects may do a Copy or a Clone based on heuristics. So probably not the exact analogue but of course rust being a lower level language it can express where and when memory is allocated.
- cyberax 4mo agoDoes it FINALLY fix the "-Xmx" nonsense? Or do I still have to statically specify the max heap size, as if I'm still using MacOS 9?
- vips7L 4mo agoMost people use percentages now for containers. -XX:MaxRamPercentage=70 But they are working on removing that: https://openjdk.org/jeps/8377305 https://openjdk.org/jeps/8377305
- mixolydianagain 4mo agomodern Java is great. But this article makes me really appreciate the class and struct features of C++
- devin 4mo agoAfter reading a lot of comments in here, there is one thing that always repeats itself in Java/JVM-related comment sections on HN. There are a surprising number of people who have an idea of what the JVM or Java used to be and have very little idea of what it is today. It is a very fit predator in 2026. Does it have its warts? Yes, but the substrate is extremely good.
- 63 4mo agoMany of us work on Java monoliths that started in the 2000s when it was in vogue and we still have to keep them chugging along on Java 8. Personally I'm familiar with all the new features that have come out in the last few years, but for my actual work, java is literally stuck in the past.
- vips7L 4mo agoAny reason why? My entire company is on 21-25. Except for one project that decided to use sun.internal.* classes.
- lotyrin 4mo agoPaying back tech debt, being able to keep up with treadmills (even slow and smooth ones) is depressingly rare.
- devin 4mo agoYeah, that would be a more nuanced take. The comments I'm indirectly referring to are people who are literally unaware of these features and talk confidently as if they do not exist.
- txdv 4mo agowhats keeping you from upgrading?
- haspok 4mo agoIn this sense, Java is already the next Cobol. I usually ask one or two questions about class loading in interviews (of senior Java devs), the younger ones are frequently stumbling upon these, and they don't even understand why I'm asking this. Good old Tomcat days, when you could run out of PermGenSpace if you weren't careful :) Good news is, Oracle extended extended extended support for Java 8 will not last forever, and eventually - if you work in a regulated industry - the company WILL have to pull the trigger. On the other hand, "where there is muck, there is brass", so a little bit of legacy can be beneficial for some.
- happyweasel 4mo agowow, basic stuff c++ had since the 80s. congrats. clap, clap, clap. now can someone please make this app that is running with -Xmx360m not use 700mb of resident memory ? asking for a friend.
- joe_mwangi 4mo agoThis time, 30mb.
- pestatije 4mo agotry reducing the heap size as it seems that's what's eating half of those 700mb
- gf000 4mo agoWhat a dumb comment. It's almost like a low-level language having a different feature set is expected. Also, there is no exact analogue, C++ is just wholly different where you can specify copy/move/destruct semantics on a gradual basis.
- petilon 4mo agoI understand the rationale for value classes, but the implementation is flawed. What will this code print: Point a = new Point(10, 10); Point b = a; a.x = 100; System.out.println(b.x); Until now the answer was obvious. Now with the addition of value classes, the answer depends on whether Point is a value class or a reference class. So readability suffers with this design. This is a violation of the principle of uniformity. In The Psychology of Computer Programming, Weinberg explains that uniformity is a psychological principle which says that users/programmers expect that things that look similar should do similar things, and conversely that things that look different should do different things. If a programming language lets two constructs look nearly identical at the use site while having meaningfully different semantics, it increases the cognitive burden on the reader. Programmers must inspect the type declaration or rely on tooling to understand whether assignment, equality, identity, and mutation behave like ordinary reference objects or like values. That can make code harder to reason about and maintain. This could have been fixed by requiring the use of the "value" keyword not just at declaration time but also at use time like this: value Point a = new Point(10, 10); Point b = a; a.x = 100; System.out.println(b.x);
- Joker_vD 4mo agoEh, still kinda murky. How about value Point a = new Point(10, 10); value Point b copy= a; a.x uniq= 100; System.out.println(b.x); Now it's much more obvious that cloning/copying takes place, and mutating a field won't affect fields of any other objects.
- zoogeny 4mo agoI believe that the statement `a.x = 100;` is invalid since Record types are immutable. That is, the situation you are afraid of should be impossible.
- petilon 4mo agoIf that's true then it is a significant improvement over structs in C#. But the distinction still matters. Value-vs-reference semantics affect equality, identity, nullability, arrays, collections, boxing, and performance. So this is not just an implementation detail. If a language hides that distinction at the use site, it increases the burden on the reader and makes code harder to reason about.
- winwang 4mo ago(Yes, not yet, but...) As a Scala afficionado, "free"/freer runtime performance is very welcome :) Fun read.
- RockieYang 4mo agoHa, just walked down a street called Valhalla in Stockholm — felt appropriate timing to read this.
- Panzerschrek 4mo ago> we want the JVM to be able to treat them as efficiently as primitives. They want basically to solve the main Java design flaw with (almost) everything is a reference paradigm. C++ and Rust have had value-types from day one. > 64 bits, including the null flag So, this basically makes every value-object optional, adds extra overhead and makes code less safe to null pointer dereference errors. > but a class with, say, two int fields or one double may not fit in an atomic write and end up as an ordinary object on the heap anyway So, the whole optimization is applied only for very small structs with no more than two scalars (or so). Did it worth to spend 10+ years of development to achieve this?
- gf000 4mo agoThat's like going to a steak bar and saying that this place sucks after the pre-dinner snacks. Java JEPs are piecemeal, there is plenty other JEPs building on top.
- zingar 4mo agoI love a long form programming deep dive. I have questions, probably basic ones that belong in undergrad CS but it’s been … a while. 1. Can someone remind me why it was so important/intentional at the start of the language that every object has identity? 2. Why is it important that we not synchronize on these value objects?
- dpark 4mo agoHow are people still defending type erasure? Sure, it was “defensible” in the sense that there were reasons the choice was made. But it was clearly a bad choice (to many people at least) when it was made and the effects are still rippling through the ecosystem. With the benefit of hindsight, it’s even more clear that the naysayers were correct and the harm to the Java ecosystem from type erasure is worse than the harm from creating parallel libraries would have been. If sane generics had been introduced, the non-generic collection types would be a historical oddity by now and we wouldn’t be talking about how a future enhancement is going to undo the erasure decision.
- hyperpallium2 4mo agoThis beaurcratic development feels like turning a super-tanker that's connected to a hundred other super-tankers. While I accept the priority of back-compatibility, I personally lack the working memory to manage it, while creative problem-solving.
- capr 4mo agoThat smells a lot like Facebook making a php compiler