Join the discussion

Write your take first — we'll ask for email only when you're ready to publish.

  • Hacker News
  • > Will I get a fast, flat `ArrayList<Point>`? Not yet.

    Sad. Hope they can do this by the next LTS JDK.

  • Yup. 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.
  • As 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.

  • > [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.

  • Footnote 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?
  • > 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?

  • That'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.

  • A bit fuzzy and dramatic; luckily the original documents are quite readable:

    top-level page: https://openjdk.org/projects/jdk/28/spec/

    JEP status: 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.)

  • FWIW both Swift and Rust have had value types and generics that abstract over unboxed values since the start.
  • I 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.

  • Functionally 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.

    by rf15
  • The C# equivalent to Java ‘value class’ would be a class with a struct encapsulated for data. The data is flattened and allocated on the heap like Java. Similarly, escape analysis could stack allocate the class at runtime, and they can be scalarized like C# structs.

    Java ‘value class’ only flattens if the total size of the class data fits within an atomic read/write op. You can force it to flatten, but you may have tearing like C# struct.

  • I made a comment on my understanding of the difference in implementation here: https://news.ycombinator.com/item?id=48606173

    The ramifications for backwards compatibility is that the JVM won't have CLR features such as stackalloc (allocation of blocks of memory on stack), ref parameters (pass-by-reference of stack allocated value types), and all the other low-level/high-performance programming features available in the CLR.

  • The 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.

  • C# actually has a fair amount of gotchas and Java aims to make these explicit. So where C# mostly copied C from a low level perspeCtive, the Java guys approached this high level and analyzed in detail which constraints give you what kind of benefit.

    So where in other languages, the struct/class taxonomy is binary, Java allows more granular control, reflection the semantics of the underlying domain. Snd as it turns out, structs have a wide range of footguns, especially in a parallel context.

  • > 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.

  • the whole point of value class is that they should not encapsulate state, i.e. its a totally transparent data holder
  • If 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.

  • I wanted to comment on this as well. The article mentions it but if you've never used Java in anger (is there any other way?) then readers may not understand the true implications of this because it's a breaking change, something Java rarely does. I'll explain for the non-Java people.

    Java separates checking identity and equality for objects. == basically checks if two pointers are the same. Equality is a subjective concept based on an interface (ie equals/hashCode). So this means:

        new Integer(1000) == new Integer(1000) // true, used to be false
        new Integer(1000).equals(new Integer(1000)) // true
        new Integer(10) == new Long(10) // compiler error, used to false
        new Integer(10) == new Integer(10) // true
    
    There's a lot going on here. The complication is that in previous versions of Java (and I'm not sure when this changed), integers below a certain value would be replaced with canonical types below a certain value. I think it was 128 but its's been awhile. This led to the difference between 10 and 1000. That's now changed, I suspect because the above comparisons are being implicitly unboxed. That didn't used to happen either. I saw this because the Integer/Long comparison used to return false and it's now a compiler error so there must be unboxing going on.

    You may still be able to get the old behavior through variables too.

    Anyway, if value classes lose identity then == changes from pointer equality to bitwise equality. That will hopefully resolve a bunch of corner cases like this but it is a breaking change, technically.

  • Value types are a concept very far away from the "magic black box organism" school of OOP thinking. It's not a novel way of doing classic OOP (does anyone still do that?), it's a way for a language born in OOP ideology get one step further into the post-OOP world.
  • You 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

  • And the only syntax change is adding 'value'.
  • A 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!

  • To take your analogy further, not only was it thrown in the garage, but it was used to sue for billions of dollars in child support (Google) so really it had just become a cash grab.

    Anyway, I wouldn't even call Java "stunted". It made choices, some reasonable, some not, and those are incredibly hard to fix later. Heck, just look at C++. Semi-compatibility with C is (IMHO) an unfixable 150 foot albatross around its neck and so many versions from C++11 onwards have simply been about making that 150 foot albatross more bearable.

    I personally think treating all value classes as a single L-type in the JVM (like primitive types, basically) is a fairly neat solution to a difficult problem. But all this comes down to the original Java 2 decision to implement generics as type erasure to maintain backwards-compatibility, something that C3 NOPEd out of as a result.

  • >> I will continue to enjoy writing once and deploying anywhere!

    Except to the browser, iOS, embedded systems...

    WebAssembly is the real write once deploy anywhere tech now. JVM had its turn and lost.

  • Yeah. I agree. As a C# fan I discovered one day the change process and release notes. Like C# it does still have strong momentum in the language design space. It was a joy observing the last 10 releases.
  • > 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.

    These two statements are contradictory. The last Java version under Sun was in 2006. Oracle bought Sun in 2010. JDK 7 came out in 2011 and JDK 8 in 2014.

    The team largely remained the same, and the main difference was that Oracle ended the neglect and funded us more, which is why Java picked up the pace after the acquisition.

    > its basically been playing catch up.

    Catch up with who or what? There are only two languages in the world as popular as Java or more: JS/TS, and Python. People who are saying Java is "playing catch up" usually compare it to languages that are doing far, far worse than Java. It's just that people who like certain features think that the language that has them is doing poorly despite them and not because of them. Many times I see people insist that other languages are "doing it right" (or better than Java) even though it is clear that the people who say this are in the minority when it comes to preferred features.

    > 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.

    If anything, the opposite is the case. Managers love to see things ship quickly. It is our technical leadership - all people who were there in the Sun days - who insist we have to move deliberately and carefully and get things right. You can agree or disagree with the decisions, but comparing Java unfavourably to languages that are doing far worse is unconvincing.

    Rather, what I think the vibe is because Java is not as popular as it was in, say, 2003. And it certainly isn't. But guess what? No other language is, either, because that time was anomalous not only for Java, but for the entire software ecosystem, which had never been as consolidated and unfragmented before or since.

    by pron
  • It was neglected during its last few years at Sun. Oracle started moving it forward at never before seen pace, while mostly maintaining backward compatibility (unlike .NET that "did things right from the start", which is what .NET Framework/.NET Core/.NET split/rewrite is according to some in this very discussion. And .NET had Java to copy and learn from, but still fucked up.)

    Same with MySQL, btw. "Dead" according to this site, risen from the dead under Oracle for those who actually know it.

  • > 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.

  • After 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.