https://kotlinlang.org logo
#getting-started
Title
# getting-started
e

Eryk Lepszy

01/26/2023, 2:36 PM
Hi, I found this question on stackoverflow about extending a data class from a sealed class: https://stackoverflow.com/questions/44419997/extending-data-class-from-a-sealed-class-in-kotlin The answer mentions something that I'm not quite sure about - that in case of using `open val`/`override val` an extending class will hold the same field twice. Is this true? Does that mean that in case of a declaration like this:
Copy code
sealed class SomeSealed(open val text: String)

data class SomeImplementation(override val text: String) : SomeSealed(text)
the field
text
is not actually overridden, but just hidden by the new declaration?
s

Sam

01/26/2023, 2:43 PM
Yes, that’s just the nature of how overrides work. The implementations of
open
properties and functions still exist even after they’ve been overridden. For example, a subclass can call its superclass’s functions and property accessors using the
super
keyword: https://kotlinlang.org/docs/inheritance.html#calling-the-superclass-implementation
e

ephemient

01/26/2023, 5:40 PM
if you
Copy code
sealed class SomeSealed {
    abstract val text: String
}
data class SomeImplementation(override val text: String) : SomeSealed()
then there is only one implementation of
text
2
e

Eryk Lepszy

01/26/2023, 6:11 PM
I wanted to avoid this, because I wanted to use another property that is initialized based on `text`'s value that will be used in all subclasses, for example like this
Copy code
sealed class SomeSealed(open val text: String) {
    protected val initialized = text.drop(1)
}

data class SomeImplementation(override val text: String) : SomeSealed(text) {
    val derivedText = initialized.drop(1)
}
But I still needed
SomeImplementation
to be a data class and I wanted to keep only one text field. Doing something like that with the
abstract val
approach unfortunately wouldn't initialize everything in the right order. Eventually I changed to the
abstract val
variant and duplicated the initialized field in subclasses, as it was the easiest solution.
s

Stephan Schröder

01/27/2023, 8:08 AM
why do you use
override val
in
SomeImplementation
in the first place? I'd just drop that and let
text
be a parameter there.
Copy code
sealed class SomeSealed(val text: String) {
    protected val initialized = text.drop(1)
}

data class SomeImplementation(text: String) : SomeSealed(text) {
    val derivedText = initialized.drop(1)
}
e

Eryk Lepszy

01/27/2023, 10:12 AM
@Stephan Schröder Primary constructor of a data class can only have property parameters. You can't do something like this
s

Stephan Schröder

01/30/2023, 9:15 AM
@Eryk Lepszy good point, but you can drop the
data
. Alternatively you could improve on @ephemient’s suggestion by using getters or lazy properties:
Copy code
sealed class SomeSealed {
    abstract val text: String
    protected val initialized: String
        get() = this.text.drop(1)
}
data class SomeImplementation(override val text: String) : SomeSealed() {
    val derivedText: String
       get() = initialized.drop(1)
}
or if you don't want to compute the value every single time
by lazy
should work
Copy code
sealed class SomeSealed {
    abstract val text: String
    protected val initialized: String by lazy {
        this.text.drop(1)
    }
}
data class SomeImplementation(override val text: String) : SomeSealed() {
    val derivedText: String by lazy {
       this.initialized.drop(1)
    }
}
But actually first you should make sure that ephemient's solution doesn't work. Now that I think of it, it actually might, even with your additions. Since SomeSealed is abstract, the text-field will (should 🤔) exists when the initialization is executed
Copy code
sealed class SomeSealed {
    abstract val text: String
    protected val initialized: String = this.text.drop(1)
}
data class SomeImplementation(override val text: String) : SomeSealed() {
    val derivedText: String = this.initialized.drop(1)
}
e

Eryk Lepszy

01/30/2023, 11:16 AM
@Stephan Schröder I mentioned earlier that I needed it to be a data class, so I don't want to drop the
data
In case of your last example that won't work, because the base class initialization is done first: https://kotlinlang.org/docs/inheritance.html#derived-class-initialization-order I really like the
lazy
example though, I didn't think of using it there. I'm not completely sure if it will fit my exact use-case, but that looks like a better solution for what I was looking for. Thank you!
s

Stephan Schröder

02/02/2023, 5:46 PM
@Eryk Lepszy You're right. I thought dynamic dispatch would come to the rescue but I checked it on Kotlin Playground and it doesn't 😅
lazy
it is 🤷‍♂️
19 Views