dephinera
05/10/2021, 1:12 PMRoukanken
05/10/2021, 1:53 PMvalue classes, which are exactly same semantically as records - their values are only defined by their constructor parameters
Yes, currently you can only have one field in them, but afaik there is plan to get rid of this restriction, which would turn them semantically same as Java recordsdephinera
05/10/2021, 2:07 PMNir
05/10/2021, 2:39 PMNir
05/10/2021, 2:39 PMNir
05/10/2021, 2:40 PMNir
05/10/2021, 2:41 PMcopy method.Nir
05/10/2021, 2:42 PMchristophsturm
05/10/2021, 2:49 PMThe real fatal flaw with kotlin dataclasses is that you can’t really have any invariant in them, because of thecan you give an example for that?method.copy
Nir
05/10/2021, 2:49 PMNir
05/10/2021, 2:50 PMNir
05/10/2021, 2:51 PM.copy to create an instance of your dataclass with an empy stringchristophsturm
05/10/2021, 2:51 PMNir
05/10/2021, 2:52 PMZach Klippenstein (he/him) [MOD]
05/10/2021, 2:55 PMchristophsturm
05/10/2021, 2:57 PMNir
05/10/2021, 2:58 PMNir
05/10/2021, 2:58 PMNir
05/10/2021, 3:00 PMRoukanken
05/10/2021, 3:00 PMNir
05/10/2021, 3:00 PMRoukanken
05/10/2021, 3:00 PMchristophsturm
05/10/2021, 3:01 PMNir
05/10/2021, 3:01 PMchristophsturm
05/10/2021, 3:03 PMchristophsturm
05/10/2021, 3:03 PMdata class A(val name:String) {
init {
if (name != "blah")
throw RuntimeException("must be blah")
}
}
val a = A("blah")
val c = a.copy("bleh")
println(c.name)christophsturm
05/10/2021, 3:03 PMNir
05/10/2021, 3:04 PMNir
05/10/2021, 3:04 PMchristophsturm
05/10/2021, 3:05 PMata class A(val name:String) {
val b = kotlin.run {
if (name != "blah")
throw RuntimeException("must be blah")
}
}
val a = A("blah")
val c = a.copy("bleh")
println(c.name)
fails tooNir
05/10/2021, 3:05 PMNir
05/10/2021, 3:05 PMchristophsturm
05/10/2021, 3:06 PMchristophsturm
05/10/2021, 3:06 PMAsq
05/10/2021, 3:07 PMdephinera
05/10/2021, 3:40 PMdata class A(val str: String)
I get:
public final class A {
@NotNull
private final String str;
@NotNull
public final String getStr() {
return this.str;
}
public A(@NotNull String str) {
Intrinsics.checkNotNullParameter(str, "str");
super();
this.str = str;
}
...
@NotNull
public final A copy(@NotNull String str) {
Intrinsics.checkNotNullParameter(str, "str");
return new A(str); // Calling constructor
}
// $FF: synthetic method
public static A copy$default(A var0, String var1, int var2, Object var3) {
if ((var2 & 1) != 0) {
var1 = var0.str;
}
return var0.copy(var1);
}
...
}
So I don't get why @Nir said it doesn't call the constructor. It's also not true that copy allow s you to change just one property. You can change as many as you want of them.
data class A(val str: String, val str2: String)
fun foo() {
val a = A("1", "2")
a.copy(str = "a", str2 = "b")
}Roukanken
05/10/2021, 3:43 PMdephinera
05/10/2021, 3:43 PMdata classes and the @JVMRecords annotation is just for interop (as mentioned in the article). I see lack of explicitness if data classes are intended to be used often as records, so I do hope that value classes will manage to serve that purposedephinera
05/10/2021, 3:53 PMvalue class inlined when used with just one property, but to act as records when having multiple propertiesRoukanken
05/10/2021, 3:54 PMNir
05/10/2021, 3:56 PMNir
05/10/2021, 3:57 PMdata class foo private constructor(val x: String) {
constructor(y: Int) : this(y.toString())
}Nir
05/10/2021, 3:57 PMfoo has the invariant that it always holds a string that is the representation of an integerNir
05/10/2021, 3:57 PMchristophsturm
05/10/2021, 3:58 PMdephinera
05/10/2021, 3:59 PMNir
05/10/2021, 4:01 PMRoukanken
05/10/2021, 4:01 PMchristophsturm
05/10/2021, 4:01 PMNir
05/10/2021, 4:02 PMYes, the default constructor is called, but in this case it's not the one you want/care about.
Nir
05/10/2021, 4:03 PMchristophsturm
05/10/2021, 4:04 PMNir
05/10/2021, 4:04 PMchristophsturm
05/10/2021, 4:04 PMRoukanken
05/10/2021, 4:04 PMNir
05/10/2021, 4:05 PMchristophsturm
05/10/2021, 4:05 PMRoukanken
05/10/2021, 4:06 PM.copy() on your class has no way to know how to call the secondary one with just String)
calling copy from not private environment, on classes with primary constructor private is basically madnessdephinera
05/10/2021, 4:06 PMNir
05/10/2021, 4:07 PMchristophsturm
05/10/2021, 4:08 PMRoukanken
05/10/2021, 4:08 PMRoukanken
05/10/2021, 4:08 PMchristophsturm
05/10/2021, 4:09 PMchristophsturm
05/10/2021, 4:09 PMNir
05/10/2021, 4:09 PMchristophsturm
05/10/2021, 4:10 PMNir
05/10/2021, 4:10 PMNir
05/10/2021, 4:10 PMNir
05/10/2021, 4:11 PMchristophsturm
05/10/2021, 4:11 PMNir
05/10/2021, 4:11 PMRoukanken
05/10/2021, 4:12 PMNir
05/10/2021, 4:12 PMNir
05/10/2021, 4:13 PMNir
05/10/2021, 4:13 PMchristophsturm
05/10/2021, 4:14 PMchristophsturm
05/10/2021, 4:14 PMNir
05/10/2021, 4:14 PMNir
05/10/2021, 4:14 PMRoukanken
05/10/2021, 4:21 PMdata class Foo private constructor(val x: String) {
constructor(y: Int) : this(y.toString())
public fun copy(y: Int? = null): Foo = Foo(
y = y ?: this.x.toInt()
)
}
Foo(4).copy(y = null)
(which the private on the other one, should be able to handle)Roukanken
05/10/2021, 4:24 PM