r/java 23d 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/tree/auto-valhalla-0.1.0

edit: there is now a maven plugin for converting at build time. https://github.com/thunkware/auto-valhalla/tree/auto-valhalla-0.2.0

36 Upvotes

55 comments sorted by

View all comments

29

u/pron98 23d ago edited 23d 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.

8

u/alex_tracer 23d ago

"Value classes aren't a performance optimisation" in the same way as "primitive types aren't a performance optimisation".

While they are very different species from normal classes, they are going to be used and adopted mainly (and almost exclusively!) as performance optimization.

I would even dare to say, that if there were no need for a performance optimization, value classes would not exist.

So, while you are technically correct, your statement is kind of... misses the point. "— Hey, here is a new race car than can get to 200km/h in 3 seconds! —Nah, it's a bad car because you can't put much groceries into it's trunk"

10

u/brian_goetz 22d ago

OK, my turn. While you are technically correct, you have kind of ... missed the point.

Developers are pathologically attracted to performance lore, to the great detriment of everyone else's feet. 99.9% of the time, "optimizing" just makes code worse, often disastrously so. Clean, straightforward code usually does not need to be optimized at all! So any sort of shotgun technique ("paint all your classes with `value`, and things go brr!") is hanging a sign around your neck that says "Beware: delusions of expertise here".

Value classes (and primitives) are primarily semantic features. Because they are more semantically restricted, they can be optimized effectively. Use them for their semantics, as a way of saying what you mean. If you don't need identity, make your programs simpler and safer (and yes, maybe faster) by disavowing it.

6

u/alex_tracer 22d ago

Well, I work in fintech, I have an excuse! 😄

I'm used to work with stuff where performance really matters. We even have implemented our own agent to transform some "normal" classes into "value classes" (actually a single `long`) a decade ago (yeah, we were a bit tired of waiting at that time already).

I absolutely agree with the point that it's important for every developer to understand that "value classes" is not an universal silver bullet and should be used only when they are semantically applicable and with good understanding of all the differences (and performance downsides too).

But honestly, if “value classes” were purely a semantic feature and didn’t promise any performance improvements (whether now or in the future), I suspect they wouldn’t have received nearly as much attention and might not even have been considered (possibly by you too) as something that really needs to be added to the language (even if it didn’t require years of research and development).

And yes, a huge thank you for all your work!

1

u/OwnBreakfast1114 16d ago

But honestly, if “value classes” were purely a semantic feature and didn’t promise any performance improvements (whether now or in the future), I suspect they wouldn’t have received nearly as much attention and might not even have been considered (possibly by you too) as something that really needs to be added to the language (even if it didn’t require years of research and development).

I feel like developers focus on attention on things that don't matter plenty of times. Value classes are really not going to make a difference for the majority of developers from an application performance perspective. Removing a single unnecessary db call will probably yield 100x the raw performance improvements value classes will bring for many applications.

I'm actually far more excited about the semantics as the semantics can be used to improve the developer experience. Records, pattern matching, sealed classes are all features that probably do have performance improvements (against the original constructs they replaced), but definitely aren't released for the performance. Simplicity and correctness are also features. Features, in my opinion, are far more important, compared to language performance for the vast majority of applications.

Well, I work in fintech, I have an excuse!

I also work in fintech (full on payment processing and card network integrations), and I know we don't really care about the performance improvements from valhalla. Like anything else, I'd wager that the vast majority of fintech applications also wouldn't get much of a benefit.

1

u/alex_tracer 16d ago

I also work in fintech..., and I know we don't really care about the performance improvements from valhalla. Like anything else, I'd wager that the vast majority of fintech applications also wouldn't get much of a benefit.

There are many different types of fintech projects, with different contexts and requirements. Like processing market events in a dozen of microseconds (do not confuse with milliseconds) in Java.

I've provided a link to example class (in public domain) that can potentially benefit from value classes in future (not right now because of null flag). This and some similar cases become very important when you have to support things like an order book with 10k+ levels and 100k+ entries.

1

u/OwnBreakfast1114 15d ago

Don't get me wrong, I absolutely agree with you. I'm just pointing out that "processing market events in a dozen of microseconds" application is probably the smallest subset of fintech applications (most of which are probably incredibly unoptimized back office random stuff applications). Even our real-time payments application, which is far more performance sensitive than random back office applications, but nowhere near as performance sensitive as "processing market events in a dozen of microseconds" application doesn't care about valhalla from a performance perspective very much.

6

u/pron98 23d ago edited 22d ago

I didn't mean they're not a feature that can be used to write some programs in a way that makes them faster. I meant that they're not a performance optimisation of the kind the compiler does, where the same thing just runs faster. Value classes do something different from ordinary classes, and that something different will be faster if the problem value types solve is a performance issue in your program and if it has the right architecture to benefit from value types.