My intended goal is to extend multiple classes from an existing library by a fixed set of attributes and methods (whose names will not overlap).
The straight forward solution would be simple inheritance: derive the library class and add the attributes/methods. But it would be quite repetitive as the attributes and methods will be the same for all derived classes. It would be better to create an auxilliary class with all attributes and methods I need and simply derive the extended classes from both the library class and the auxilliary class.
However, as it seems there is no multiple inheritance in Kotlin comparable to C++ , I wanted to use interfaces to make it work, where the interface would hold all the attributes and methods I need.
I have started with the following simplistic code to test interfaces:
open class LibraryClass{
var x: Int = 0
fun setMyX(x_: Int){
x = x_
}
}
interface MyInterface{
var y: Int
var z: Int
var abc: Int
fun myMethod(y_: Int){
y = y_
z = y*y
}
}
class InheritanceTest: LibraryClass(), MyInterface{
fun print(){
println("My values: $x, $y, $z")
}
}
fun main(){
var test = InheritanceTest()
test.setMyX(1)
test.myMethod(5)
test.print()
}
If I try to compile this code, I will get the following error message:
error: class 'InheritanceTest' is not abstract and does not implement abstract member public abstract var y: Int defined in MyInterface
Some research showed that I need to override the interface's attributes in the primary constructor of the derived class:
class InheritanceTest(override var y: Int, override var z: Int, override var abc: Int)
and then
var test = InheritanceTest(2,3,0)
Overriding all(?) interface attributes (even unused ones) in the derived class seems quite repetitive (and it's not possible to initialize attributes in the interface either), which basically beats the purpose of why I originally intended to use interfaces: to save repetition. (Except for methods, which seem not to have to be overridden as long as one class and (multiple) interfaces do not share methods of the same name).
My interposed question is: Is this the only way to do it or solve the error?
Then I found something else to try out in the interface:
var fgh: Int
get() { return fgh }
set(v) { fgh = v }
No overriding necessary so far. But I could not yet get how to actually use the attribute fgh in either a method or by setting a value.
When I try to set fgh by test.fgh = 100
in main()
, I get the following error:
Exception in thread "main" java.lang.StackOverflowError
at MyInterface$DefaultImpls.setFgh(
Then trying to use test.setFgh(100)
(since the previous error message implies the method exists) yields:
error: unresolved reference: setFgh
Trying to define setFgh(v: Int) {fgh = v}
results in:
error: platform declaration clash: The following declarations have the same JVM signature (setFgh(I)V):
fun <set-fgh>(v: Int): Unit defined in MyInterface
fun setFgh(v: Int): Unit defined in MyInterface
Alright, defining a differently named method similar to myMethod()
:
fun myOtherMethod(v: Int){
fgh = v
z = fgh * fgh
}
And then using myOtherMethod(10)
in main()
gives again:
Exception in thread "main" java.lang.StackOverflowError
at MyInterface$DefaultImpls.setFgh
So, I'm now really lost as to what do in order to get a non-repetitive working solution for extending multiple classes with the same attributes and methods.
Edit: I now understand that interfaces aren't exactly what I was going for, as one has to implement (not override, which took me a while to get as it is done by the keyword "override") everything in the derived classes.
You were on the right track with your first try. You really have to override the attributes in the interface, but it doesn't have to be done in the constructor. You can do it in the class body and that way you can add a default value for them (not only can, but you must). If you make that class open you can then extend from it in all your classes.
open class InheritanceTest: LibraryClass(), MyInterface {
override var y: Int = 0
override var z: Int = 0
override var abc: Int = 0
fun print() {
println("My values: $x, $y, $z")
}
}
With this class your original main will print My values: 1, 5, 25
, and you will be able to inherit from this class without having to override/initialize anything (but you can use the init
block to customize your superclass). For example:
class MyClass : InheritanceTest() {
init {
myMethod(4)
}
}
fun main() {
val test = MyClass()
test.setMyX(2)
test.print()
}
will print My values: 2, 4, 16
I hope I understood your question correctly and could help :)
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