In java,
abstract class NumericValue{
private String a;
private String b;
public String getA() { return a; }
public void setA(String a) { this.a = a; }
public String getB() { return b; }
public void setB(String b) { this.b = b; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NumericValue that = (NumericValue) o;
if (a != null ? !a.equals(that.a) : that.a != null) return false;
return b != null ? b.equals(that.b) : that.b == null;
}
@Override
public int hashCode() {
int result = a != null ? a.hashCode() : 0;
result = 31 * result + (b != null ? b.hashCode() : 0);
return result;
}
}
class Abc extends NumericValue{
public static void main(String[] args) {
Abc abc = new Abc();
abc.getA();
}
}
In Kotlin, this boils down to:
Approach 1:
sealed class NumericValueA{
abstract var a: String
abstract var b: String
}
data class AbcA(
override var a:String,
override var b:String
):NumericValueA()
Approach 2:
open class NumericValueB(
open var a:String,
open var b:String
)
data class AbcB(
override var a:String,
override var b:String
):NumericValueB(a,b)
Both approaches tend to massive duplication when you have data classes that simply inherit attributes since you have to write down everything you specified again - this simply doesn't scale and somehow feels wrong.
Is this state of the art or is that really the best way to translate the former java code to kotlin?
IntelliJ Idea translates your Java code into the following which seems reasonable and reduced in boiler plate. So, I would answer, "No, your premise does not accurately characterize whether or not Kotlin is state of the art ".
But, your question specifically targets "data" classes. Data classes are a nice component of the language that gives us "deconstruction" and some useful automatically generated methods for deconstruction (such as
componentN
). So, using the code above (and addingopen
to class and the declarations ofa
andb
), here is slightly different implementation of your example derived class.Which seems reasonable, in that, your starting example is not a data class and your apparent desire is to make use of the Kotlin data class. It gives you a desirable feature (if you need it), at the cost of a little more code verbage.
The derived class is the same code if you declare the base as
sealed
anda
andb
asabstract
.So, in the case of data classes, there is duplication of any part of the base class that you want to expose as "data" in the derived class (it's already exposed, just not as "data class" special members, as shown in the example below). But this is analogous to overrides in other contexts. Just for thought, consider now the following derived class.
You get all the members of base class, and the new data members of the derived class. But if you want override benefits, it again costs some syntactic verbage (for derived data classes and regular classes).
One last point. Data classes still have other weirdness-es associated with inheritance and overrides that may still have to be worked out.
toString
,hashCode
andequals
get their own special implementations and the documentation says...... which I find to be confusing to read (leading me to experiment rather than rely upon the docs). And there are other SO questions dealing with struggles over
toString
and data classes (for example: this OP trying to create a DTO).So, I think this is the state-of-the-art and it's not that bad (IMO). And yes, if you want the features of data classes, you can translate it pretty much as you've done.