You are currently viewing Assuming the data class’s generated copy() is unacceptable, what’s the best way to implement a value type?

Assuming the data class’s generated copy() is unacceptable, what’s the best way to implement a value type?

I do not want a debate about data class’s auto-generated copy() method and what someone should or should not do with data classes.

Let’s just assume that someone wants to write a class whose identity is determined only by the value of its stored properties, but they want a non-public constructor (which is undermined by data class’s copy()).

It seems to me that we have approximately three options:

  • Regular old class with equals(), hashCode(), and toString() implemented “by hand”.

  • Using @jvmRecord annotation on a regular class, which will generate equals(), hashCode(), and toString(), componentN(), but not a copy().

  • Using this compiler plugin library: https://github.com/AhmedMourad0/no-copy

  • Eventually, Kotlin’s native value classes are supposed to be expanded to support more than a single field. But that’s dependent on project Valhalla landing on the JVM, so I don’t think we should hold our breath waiting for that.

The flaw with the “by hand” approach is the same old story: if you change your class you have to be very careful to remember to update all the methods. It’s also more noise for a reader- they don’t know if your equals() implementation is just boilerplate or if you’re actually doing something interesting, so they’re forced to study it carefully.

The flaw with the @jvmRecord annotation is that all Record classes inherit from a base Java class, which means that your class can’t inherit from any other class. There may also be other issues/papercuts I’m unaware of (compile time? generated method name issues? runtime performance issues?).

The flaw with the no-copy approach is that you have to globally disable IDE warnings to avoid false-positives (although, it looks like that might be fixed now?), and just that it’s a compiler plugin- so it might (“probably will”, if you’re cynical like me) break on Kotlin version bumps. I also don’t know if it will affect compile times.

It seems like the no-copy plugin is probably the best bet today. Is there any option I’m missing?

submitted by /u/ragnese
[link] [comments]