Hacker News new | ask | show | jobs
by throwpupper 1874 days ago
I think the article is misleading in the list of advantages over Kotlin's Data Classes.

1. Destructuring - available in Kotlin

2. Copy with change - available in Kotlin

3. Serialization - not sure why Kotlin data class would not be serializable

4. Boilerplate - Kotlin takes care of equals and hashCode

Huge disadvantage that matters to me is that record fields cannot be mutated. It makes the records much less useful.

2 comments

"Huge disadvantage that matters to me is that record fields cannot be mutated. It makes the records much less useful."

No. It makes them much more useful.

Well it means that the second you need a setter you can't use records so all the boilerplate remains.
You are supposed to create a new copy with some of the fields changed. Just like you do it with the java.time.* classes and others.
Yet the only mechanism for this is error prone or relying on mountains of boilerplate.
Instead of changing few bytes, now I have to copy hundreds of bytes around and add more stuff for GC to collect.

Well, they have to obey Wirth's law, I guess.

I mean, you do realize that you're writing Java code right? If you want ultimate low level optimization and control then you're already about ten miles too far downstream to make that turn. Also, I'm guessing the copy overhead is more than offset by the JVM being able to do better optimizations around these data structures.
Structs with mutable fields is hardly “ultimate low level optimization”, it’s something a lot of programmers still use as a matter of course. (I say this as a fan of immutable data!)

Ultimate low-level optimization in Java would be more like packing your structure into arrays of integers - which is something people actually do in Java. Just because you’re using Java doesn’t mean you don’t want your code to run as fast as possible.

I don't know if the JVM developers have actually implemented this, but since records are immutable, there's no reason why a copy couldn't share memory between the instances.

The major downside is that could ruin cache locality and make passing the instance across a FFI boundary require a copy.

Another optimization would be that the JIT (or even perhaps javac) could notice cases where you make a copy (with one field changed) of a record and then never use the original reference again. If the JIT (or javac) can prove that no other bit of code holds a reference to the original record, it can reuse and mutate the original one instead of making a copy. I don't know if this optimization is or will be implemented, of course.

Either way, I expect the overhead you mention ends up being worth the benefits of immutable data. (That's been my experience using Scala, anyway.)

This has been argued ad nauseam around the time Scala started gaining traction because scala's collections are grouped into immutable and mutable. The consensus at the time is that the GC overhead is well worth the ability to parallelize computation.
You have to copy less than you think. Because the data is immutable, you can share everything but the changed fields.
Then you've invented mutability without references/identity. Except those are desired properties for data classes, unlike for value classes which have such semantic difference.

Btw Kotlin allow to make immutable Java records too so clear winner.

Or you know, the JIT will trivially optimize away the old class if it is reassigned to the same variable, as you would use it inside a loop. How do you think the litany of FP languages work? Like Haskell, Scala, Clojure?
It can be done in theory, but the JVM does nothing of the sort right now.
That's a theory not happening in practice. In practice Java programs are slow and memory-hungry because of those issues when some people think that it's cheap to create small objects or that escape analysis will solve their issues without verifying that it works for their case.
GC is there for a reason, unless you do HFT, use it to your advantage.
You write java and worry about bytes copied?
Yes, I do. Java could be quite fast if you won't slow it down on purpose.
Why would you need a setter for a data class? They add no value there.
1. with possible loss of information 2. as API, but an operator can do more 3. they are surely serializable, but they still need all the ugly reflection hacks that come with that (like bypassing the constructor and allowing the JVM to write to final fields) 4. that part was just presenting a benefit of records (on its own; not over Lombok/Kotlin), but the fact it's under the header "Why Records Are Better*" is confusing