Options 3 and 4 would result in the class holding messageId
twice. Once in the new class and once in its superclass.
The solution is to declare but not define the variable in the superclass:
sealed class Message {
abstract val messageId: String
}
data class Track(val event: String, override val messageId: String): Message()
This will make the messageId available on Message
, but delegates the storage to whatever implements it.