I have a parent class as following,
interface ITask { }
open class Task(val targetServer: Server) : ITask { }
Then there a child inheriting it and overriding the primary constructor as following,
data class FileTask(val sourceServer: Server, targetServer: Server) : Task(targetServer = targetServer) {
}
This is throwing a compilation error in eclipse as
Data class primary constructor must have only property (val / var) parameters
Removing the data
keyword from the class header will kill the error, but I don't understand why.
Keeping the data
keyword and adding var
to the targetServer
gives another error
'targetServer' hides member of supertype 'Task' and needs 'override' modifier
Adding override
to the targetServer
to be override var targetServer: Server
throws another error
'targetServer' in 'Task' is final and cannot be overridden
I need some help to understand these errors.
The initial error is because a data class can't have parameters in its primary constructor other than val
or var
properties. Removing the data
keyword lifts this restriction.
It's been mentioned that data classes generally don't play well with inheritance. They're supposed to be used as simple data transfer objects, and aren't really suitable for participating in hierarchies, because it becomes hard to understand which properties are going to be considered in the implementations of the generated methods. Your best bet might be to not use them at all here.
For more about data classes and inheritance, here is the proposal that was implemented in Kotlin 1.1.
To get back to the specific problem, if you really have to make this class a data class, you can mark the property in the base class as open
and then override it in FileTask
, like so:
open class Task(open val targetServer: Server) : ITask
data class FileTask(val sourceServer: Server, override val targetServer: Server): Task(targetServer = targetServer)
This basically hides the property declared in Task
, and always accesses the property in FileTask
instead.
I don't know what your exact requirements for your classes are, but one thing you could do to clean this up and make it a bit nicer would be to make Task
and its targetServer
property abstract, like so:
abstract class Task : ITask {
abstract val targetServer: Server
}
data class FileTask(val sourceServer: Server, override val targetServer: Server) : Task()
This way you wouldn't have the unnecessary property (and backing field) in the base class, and you'd be forced to have a targetServer
property in all the classes that inherit from Task
. You could also take this a step further, and put the property in the ITask
interface as well.
interface ITask {
val targetServer: Server
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With