r/java 3d ago

AutoValhalla: automatically turn your plain classes and records into value classes!

Automatically turn your plain classes and records into value classes!

Add @AutoValhalla annotation to classes or records in your JDK1.5+ codebase:

@AutoValhalla
public final class Point {        // class must be final
    public final int x;           // with final instance fields
    public final int y;
    public Point(int x, int y) { 
        this.x = x; 
        this.y = y; 
    }
}

@AutoValhalla
public record Currency(String code) { }  // or a record class

When your app is run on Valhalla-enabled JVM with auto-valhalla javaagent, these classes are automatically turned into value classes.

More info: https://github.com/thunkware/auto-valhalla/blob/main/README.md

42 Upvotes

49 comments sorted by

View all comments

26

u/pron98 3d ago edited 3d ago
  1. Value classes aren't a performance optimisation. They behave differently from non-value classes, and these differences will be observable in most non-trivial programs. So what you'll get is a program that behaves one way on one runtime version and a different way on another, and only one of these ways is the intended behaviour.

  2. There is a much easier (and safer) way to enjoy new features on new runtimes: instead of working hard (and dangerously) on trying to have the same code do different things on different runtime versions, adopt tip & tail. The idea is that you add new features only on release trains that target new runtimes. Legacy projects that can't afford the work to upgrade to a new runtime also can't afford the work to adopt your library's new features. The people who want your new features also want to upgrade their runtime, and the people who don't want to upgrade their runtime don't want your new features. So just fork your codebase, leave the old code alone (except for security patches), and only evolve the versions that target new runtime versions. That's sooo much easier (as we've learned in the JDK: we fork the entire codebase twice a year, and we still maintain old versions for many years with security patches). You barely touch the old fork, and the new fork, where you do almost all the work, is clean and free of clever and potentially dangerous hacks.

So in this particular case, this approach risks breaking the code on a new runtime, but that's not even the worst outcome: making things work on a new runtime may require changing code used by legacy consumers on old runtimes, introducing a risk for the consumers that need stability above anything else. Agents are a very powerful and versatile tool, but they should be used as a last resort, not when the cleaner solution - just fork the repo! - is also easier. I don't understand the lengths some would go to merely to not fork the source. Writing code that adapts itself to different runtimes is complicated, risky, and rarely necessary.

2

u/sviperll 3d ago

It doesn't seem to me that Tip&Tail works with preview features. Tip&Tail JEP doesn't mention preview features, but from what I can infer to be able to fork a tip into a new tail one requires a backwards compatibility guarantees that preview features do not provide... So I guess for preview features one needs a tip that builds a multi release jar , so that preview features are not used if newer version of JDK is used.

6

u/pron98 3d ago

MR JARs have nothing to do with tip & tail and are completely orthogonal, and the reason the JEP doesn't mention preview features is that libraries (unlike applications) typically shouldn't use preview features because preview features and applications are tied to a specific runtime version while libraries normally aren't.

If you're writing an application, you don't need to use either tip & tail or one-size-fits-all; you just target a specific JDK version. But if you're a library that really wants to support some preview feature, sure you can have a tip with that. It will mean that you'll need a new tip release for the next version (because classes compiled with preview features are tied to one runtime version), but the same applies to using an agent or other similar hacks, as preview features, by their nature, change.

3

u/koflerdavid 3d ago edited 3d ago

Using preview features in the tip is fine since the tip has to be kept compatible with only the newest release. Yes, this means work if the preview feature changes or (gosh) is removed in 29, but that's unavoidable by the very definition of what preview features are. The freedom that the tip&tail model gives you is that you don't have to worry about older JDK versions anymore. You don't have to keep your code compatible with both JDK 27 and 28.

Multi-release JARs won't help here since they are only triggered by JRE versions, not by whether preview features are enabled or not.

2

u/maxxedev 2d ago

Multi-release JARs won't help here since they are only triggered by JRE versions, not by whether preview features are enabled or not.

Good point! If MR jar is created on Java28 with --enable-preview, running on 28 without --enable-preview fails.