It seems like there's still an outstanding issue i...
# announcements
n
It seems like there's still an outstanding issue in Kotlin, with regards to data classes with private constructors. The basic problem being that the copy method allows you to still set the members individually, and is always public, and cannot be deleted. This means that currently in Kotlin it doesn't really seem possible to write a data class in Kotlin that has any invariants amongst members which are part of its representation, which is annoying if you primarily want the data class for hashing or equality, for example. What's the recommended practice around this for now, and what direction is it headed in the future?
j
FWIW - there is a compiler plugin to deal with the copy issue: https://github.com/AhmedMourad0/no-copy
👍 1
d
copy
will still call the constructor and the constructor includes any
init  { }
blocks. For example you can do this:
Copy code
data class Foo(val nonNegative: Int) {
    init {
        require(nonNegative >= 0) { "nonNegative must be >= 0" }
    }
}
You will never have a
Foo(nonNegative=-3)
with this class, even when using
copy
.
copy(nonNegative=-3)
will still run the
init
block and throw any exceptions.
j
I think Elizarov mentioned this here:

https://youtu.be/0FF19HJDqMo

n
@diesieben07 thanks, yeah that is better than nothing, but you're trading compile time safety for runtime
d
What kind of compile time safety are you looking for? Any compile-time safety enforced by the constructor's signature is reflected by the
copy
signature.
n
I mean that if your class is written in a way that its impossible to violate its invariants, then its impossible
you can't write a compiling program that will have instances of your class with invalid invariants
Copy code
data class Point<D : Dimension> private constructor(val data: List<Int>) {
    constructor(d: D, init: (Int) -> Int) : this(List(d.dimension, init))
}
Here's my simple example (from advent of code) that had me wondering about this.
You can see that if the
copy
function doesn't exist, there's just no way to create a
Point<D>
, that doesn't obey the invariant that D's dimension == data.size
shy of really going out of your way, at least