Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Extending data class from a sealed class in Kotlin

I have a set of data classes that share some common fields, So ideally I'd like to declare those in a supertype (Message in this example), and be able to write functions that operate on the supertype if they need access to these common fields (messageId in this example).

fun operate(m: Message) {   use(m.messageId) } 

I tried to accomplish this by extending my data classes from a sealed class.

Data classes may extend sealed classes, but not I'm not sure how/if they can accept arguments required by the "supertype" sealed class.

  1. Extending a regular class from a sealed class compiles just fine.

    sealed class Message(val messageId: String)  class Track(val event: String, messageId: String): Message(messageId) 
  2. However, changing it to a data class doesn't compile ("Data class primary constructor must have only property (val/var) parameters.").

    sealed class Message(val messageId: String)  data class Track(val event: String, messageId: String): Message(messageId) 
  3. Declaring the parameter as a property also doesn't compile ("'messageId' hides member of supertype 'Message' and needs 'override' modifier'").

    sealed class Message(val messageId: String)  data class Track(val event: String, val messageId: String): Message(messageId) 
  4. Opening the supertype property and overriding it in each of the base classes compiles fine:

    sealed class Message(open val messageId: String)  data class Track(val event: String, override val messageId: String): Message(messageId) 

Ideally I would like something close to Option 2 - it allows me to combine the best of both worlds.

Otherwise, it seems my options are either handrolling my own data class functionality (copy, hashcode, equals etc) with option 1, or live with a compromise by opening up up the supertype properties with option 4.

like image 893
f2prateek Avatar asked Jun 07 '17 18:06

f2prateek


People also ask

Can sealed class extend another class?

This means the heir of the sealed class can have as many as any number of instances and can store states, but the enum class cannot. Sealed classes also offer a restricted number of hierarchies. This means if you have a different class defined in another file in your project, you cannot extend the class Menu .

How do you extend a sealed class?

Sealed classes are used to restrict the users from inheriting the class. A class can be sealed by using the sealed keyword. The keyword tells the compiler that the class is sealed, and therefore, cannot be extended. No class can be derived from a sealed class.

How do you use sealed class in Kotlin?

To define a sealed class, just precede the class modifier with the sealed keyword. The sealed classes also have one another distinct feature, their constructors are protected by default. A sealed class is implicitly abstract and hence it cannot be instantiated.

Can a sealed class inherit from another class?

Once a class is defined as a sealed class, the class cannot be inherited.


1 Answers

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.

like image 182
Kiskae Avatar answered Oct 04 '22 19:10

Kiskae