Amr Eladawy
Amr Eladawy

Reputation: 4358

Inheriting class with primary constructor

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.

Upvotes: 7

Views: 5688

Answers (2)

Manish Bansal
Manish Bansal

Reputation: 185

I know this is a very old post, but I was struggling with the same issue and making my superclass abstract was not a solution. You just need to do the following:

change this

open class Task(val targetServer: Server) : ITask { }

to (Please note, I have made targetServer variable to open)

open class Task(open val targetServer: Server) : ITask { }

Upvotes: 0

zsmb13
zsmb13

Reputation: 89548

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
}

Upvotes: 13

Related Questions