Reputation: 1
I have interface A which has interface B as a field. When I do an implementation of A, let's say concreteA, and instead of providing interface B, I provide an implementation of B, the compiler throws me an error. I don't understand why, because since there is inheritance in Kotlin, I think this should work. I tried this with data classes by the way.
interface B {
....
}
data class concreteB : B {
.....
}
interface A {
var someField: B
}
data class concreteA : A {
//The error happens here, compiler says it's not type of overridden
override var someField: concreteB
}
Upvotes: 0
Views: 223
Reputation: 18617
The definition of A
says that every implementation must have a field storing an instance of something implementing B
. This field is var
, meaning that other code can change it.
In your ConcreteA
, you're overriding that to restrict the field to hold only your ConcreteB
.
Now, that's fine for code calling the getter, as it will always get something of type B
.
But it's a problem for code calling the setter. What if they try to set some other implementation of B
? The interface says they can, but your concrete implementation can't. That's why the compiler won't allow your implementation. (That's the Liskov Substitution Principle in action, as the Kotlin guys said.)
There are several approaches you could take to make it compile:
You could use a val
instead of a var
in A
, and not allow anyone else to change the value. (Simple, but probably not what you want.)
You could parameterise A
with the type of value, giving B
as an upper bound. That would let implementations (and subinterfaces) restrict the type to ConcreteB
if they wanted to. (That's a bit more complex, but is very flexible and may be best suited to your needs.)
You could keep the type of the field as B
, and just initialise it to your ConcreteB
(as per Alexey's answer). (However, your ConcreteB
would have to allow for the possibility of other B
implementations being set later on.)
Upvotes: 1
Reputation: 17731
The fact that you inherited something from your dad doesn't mean that you're your dad.
The usage of data classes here is a bit confusing, since your code won't compile with them.
That's the correct way for your code to work:
interface B
class ConcreteB : B
interface A {
var someField: B
}
class ConcreteA : A {
override var someField: B = // That's the interface
ConcreteB() // That's the implementation
}
Upvotes: 1