Hacker News new | ask | show | jobs
by hashmash 1744 days ago
I'm trying to find a good use case for records, but the best I can come up with is using it for composite hashmap keys. I suppose when combined with sealed classes and pattern matching features at some point it might be more useful, but what is the main use for records right now? Given that they're immutable and have no convenient way to be copied when modified, I find them quite tedious to use.
10 comments

I work as a systems developer for a bank and records is an easy replacement for a very popular dependency called lombok. Now, records doesn't necessarily do everything that lombok does, but for us it replaces what we actually need. One less dependency and I'm a happy camper.
I think it's worth highlighting that while Lombok is a dependency it is only a compile time dependency (it's not part of the output JAR).
You say only, but I find that to be much more fussy.
Exactly, I hate dealing with Lombok projects for that reason. I'd rather the cruft than the compiler add-on.
Do you not just use maven? Any of the major IDEs will automatically configure annotation processors for you when they're configured in your pom. Similar for gradle.
Its been a while since I have had to deal with one, but at the time the IDE didn't handle it well at all. I think it was because I was missing the Lombok plugin.

TBH, it was a lot of trouble so that someone could avoid generating a couple of getters and setters, and could use a annotation to setup the logger. I realize that there are more features available than that, but the ones that I've seen often used it in such mundane and boring ways that the setup wasn't worth the hassle for me.

But I guess we all get annoyed with minor hassles in different ways. I got annoyed with the hassle of setting up an IDE, they got annoyed with getters and setters more. :)

I no longer think there is a justification for a project like Lombok. FreeBuilder/AutoValue (depending on your needs) will provide the same feature, but with clear visibility at the IDE level.
Honestly, I expect that half the classes I write will be records, once I have access to this.

A lot of the time, the software I'm working on has data objects that are really amalgamations of other fields. Example: "Address" is the street address, the city, the postal code, etc, etc. These sorts of objects should be immutable. Records are perfect for that.

If I need to add additional logic, methods, then you can add those to a record. But it continues to enforce that the state is immutable.

For example,

* tuples (complex numbers, points, dimensions, colors, IP addresses),

* database query results,

* stateless beans for DI frameworks where it cuts down on the verbosity of using constructor injection (actually a slight misuse)

* composite natural keys in database modeling

The immutability can help to enforce API contracts and proper service layering. A common problem in legacy code is modules communicating with each other by modifying objects that were passed as arguments.

Eventually, Project Valhalla will introduce the possibility to declare records as primitive, which will also reduce the overhead of Wither methods.

Edit: Building web APIs should also benefit from records because the argument and result types are only supposed to be created and read, not modified.

I guess records will make valhalla (value types) easier which enables more efficient data structures and will probably make passing data over FFI (valhalla) easier too.

They reduce a lot of boilerplate, e.g. when passing multiple return values.

Records are orthogonal to value types (now called primitive types).
I thought they are light weight ways of declaring a structure. From there they take different paths for immutability extensibility allocation … etc
I find records super useful! You can not only express things like a Point(x, y) easily, but you can also wrap primitive types like integer to give values semantic, behavior and typesafety. Records are the perfect fit for value types as used for example in Domain-driven Design.
We would use them as data transfer objects between different layers of the system - however, they cannot extend another class and thus are not suitable in our specific case.
Probably 1/2 of all Java classes written should be records.
No more Lombok @Data annotations needed...
Actually, I think it would be the lombok @Value. Record classes are immutable, while @Data adds set methods.
So one thing peculiar in Java is public records have to be in their own files. Now I wanted to treat records as less ceremonial than classes to organize code. I'd have liked to have a dozen or so records in a file along with some basic operations on them but it is not possible have multiple records without that many files.

I know the answer is always use IDE and all but it causes more context switches than scrolling a bit to see types I created.

If you have a bunch of related records you can make them public and nested within a top-level public class. You could also throw some static utility or factory methods in there too.
Sure, but that's still ceremony.
It's a core restriction of Java that there can only be one public class in each file. Nesting records inside a class would solve the issue. It's not that pretty though because only lower-casing the class name would create the illusion of it being a package.
I would use records a lot more (pretty much everywhere) if I could easily derive new values from existing ones.
There are some funny ways to work with records. I can recommend this article: https://benjiweber.co.uk/blog/2020/09/19/fun-with-java-recor...
Still way too much typing compared to lombok's @Value @With.
This will be solved[1]:

record Point(int x, int y) {}

Point p = new Point(1, 2); Point pp = p with { x = 3; }

[1] https://github.com/openjdk/amber-docs/blob/master/eg-drafts/...

Interesting. It's ok. It seems like they're adding this syntax just to avoid extra copies eg, `p with {x = 3, y = 4}` instead of `p.withX(3).withY(4)`. I really don't mind the later.

My gut feel is that records break encapsulation and will make refactoring slightly more difficult than the equivalent lombok value class. But if this gets more people making objects immutable, I'm all for it.

The perfect transparency of the underlying data is rather the whole point of records. Tempered by immutability, records should be a useful tool for modeling data where encapsulation is not required. Note that it is still possible to add methods that can perform computation on the underlying data.
TBH both approaches are just poor design of the object model. The one from my link is a clever but inefficient way to manipulate records (reflection), the one with Lombok is creating redundant interfaces without business meaning. A record with few business methods is lean enough and ensures that only valid transitions can happen.
Eh? This is pretty good:

   Colour changed = colour.withRed(5);
Every method of your API must serve some business purpose. "With" methods and setters generated or written "just in case" often do not have one or they are being used only in tests, which would be insufficient justification for having them. Does your code really need to change individual components of the color? If it is not a graphic editor, probably not and those methods will be redundant.