My current data model uses nullables and a state p...
# announcements
k
My current data model uses nullables and a state property to handle the objects state
Copy code
data class Model(
    val a: String,
    val b: String,
    val nullableOnlyForStateA: String?,
    val state: State,
    val propForStateA: String?,
    val propForStateB: String?
)
I’m trying to use sealed classes to make it more idiomatic but it seems too verbose:
Copy code
sealed class Model {
    abstract val a: String
    abstract val b: String
    abstract val nullableOnlyForStateA: String?

    data class A(
        override val a: String,
        override val b: String,
        override val nullableOnlyForStateA: String?,
        val propForStateA: String
    ) : Model()

    data class B(
        override val a: String,
        override val b: String,
        override val nullableOnlyForStateA: String,
        val propForStateB: String
    ) : Model()
}
This seems okay but my original class has much more properties and more states making a 16-line data class turn into a more-than-100 line sealed class. Any ideas on how to make this more ergonomic?
m
not really, it's the cost of making sure you will never encounter a problem with it once it's made vs. encountering potential checks everytime once you use it.
k
Fair enough. There’s just a lot of repeated code. I wish I can just say that every subclass has these properties without having to put all those
override
statements
n
IMHO this is a major shortcoming in Kotlin, plain and simple
No way to avoid repeating fields between data classes
The ideal approach here is to have a dataclass that contains all the common fields
And then you have a member of the sealed class type that contains only the things that differ
But that obviously changes your schema
m
Well you don't HAVE to if you don't need the constructor, but then who would be responsible for setting such data? At least all your sealedsubclasses can't be data classes than anymore. You could then technically use a builder and all, but at what cost?
k
The model is what’s in the database but I wanted to map it to a sealed class as the domain model. When I receive it, I map it out via:
Copy code
fun DataModel.toDomainModel() = when(state) {
    Case1 -> Case1DomainModel(...)
    Case2 -> Case2DomainModel(...)
    ...
}
Currently, I just have a copy of it as a domain model and it’s working so I don’t necessarily have to do this. Just trying to find ways to make it more expressive
n
What's in the ... ?
Are you performing some direct deserializing?
k
The fields
Case1DomainModel(field1 = field1, field2 = field2, …
and extra cases omitted for brevity
n
If you have to forward fields around like this anyway
Then it's not strictly necessary that your class structure match the database exactly, so you can do what I suggested
So you would leave Model as a data class, and leave in all the fields that are common to all states
And then have a sealed class, StateData
k
Yup. I totally get your idea and I’m leaning towards it
n
Cool sorry wasn't sure if I was clear :-)
k
It was and I think it’s clever. I’m glad I asked here.
👍 1