How to provide interface implementation using two combined classes? - kotlin

I have the following interface and two classes:
interface A {
fun foo()
fun bar()
}
class B {
fun foo() {}
}
class C {
fun bar() {}
}
Is it possible to somehow provide implementation for this interface using/combining those 2 classes?

One way to do this without changing the given code is to just use instances of B and C in a new class implementing A:
class D : A {
private val b = B()
private val c = C()
override fun foo() = b.foo()
override fun bar() = c.bar()
}
This doesn't scale very well though, and requires to write boilerplate.
With Kotlin you can implement interfaces by delegation, which basically does exactly the above, but automatically.
However, this requires you to split your interface A into the part that is implemented by B and the part implemented by C:
interface Foo {
fun foo()
}
interface Bar {
fun bar()
}
interface A : Foo, Bar
class B : Foo {
override fun foo() {}
}
class C : Bar {
override fun bar() {}
}
class D : A, Foo by B(), Bar by C()
If you need configurable instances of B and C, you can pass them to D via its constructor:
class D(val b: B, val c: C): A, Foo by b, Bar by c
If B and/or C have constructors that take arguments, you can create instances of B and/or C using parameters from D's constructor:
class B(val something: String) : Foo { ... }
class D(something: String) : A, Foo by B(something), Bar by C()

You can create a new class that implements this interface and delegate method invocation to these classes.
class D(val b: B, val c: C) : A {
override fun foo() {
return b.foo()
}
override fun bar() {
return c.bar()
}
}
Or if you have access to interface A, you can change it next way
interface AB {
fun foo()
}
interface AC {
fun bar()
}
interface A : AB, AC
class B : AB {
override fun foo() {}
}
class C : AC {
override fun bar() {}
}
class D(val b: B, val c: C) : AB by b, AC by c, A
So, now, your D class implements interface A using delegates

Related

Combining abstract classes somehow?

Let's say we have an abstract class A with feature A, we also need an abstract class B with feature B that extends A. Later on, we make an abstract class C with feature C that extends A.
Is it possible somehow to have an abstract class that has features B and C, without reimplementing (rewriting code) one of them?
abstract class A { fun featureA() { /* implementation */ } }
abstract class B: A() { fun featureB() { /* implementation */ } }
abstract class C: A() { fun featureC() { /* implementation */ } }
abstract class D: C() { fun featureB() { /* how can the implementation be avoided? */ } }
I don't mind if there aren't abstract classes per se, but it's required to have the implementation of corresponding feature.
Can you use interfaces? Since you're really trying to compose a class from types B and C, that's a better fit than trying to inherit from both. You can inherit from other interfaces and use their implementations:
interface A {
fun beA() { print("A!") }
}
interface B : A {
fun beB() { print("B!") }
}
interface C : A {
fun beC() { print("C!") }
}
class D : B, C {
fun beD() { print("D!") }
}
fun main() {
with(D()) {
beB()
beC()
beD()
beA()
}
}
>> B!C!D!A!
Interfaces can have properties, but not with backing fields, so they have to be abstract - you can't assign a default value in the interface. So that's a limitation you might run into vs actual abstract classes. But you can create properties with getter functions:
interface A {
val luckyNumber = 777 // nope
val luckyNumber get() = 777 // yep
}

Object expressions, Multiple supertype specification syntax?

I am new to Kotlin. I came across the Object Expressions section of https://kotlinlang.org
Some of the object expression syntaxes are very straight forward to understand,
Create an object of an anonymous class
window.addMouseListener(object : MouseAdapter() {
override fun mouseClicked(e: MouseEvent) { ... }
override fun mouseEntered(e: MouseEvent) { ... }
})
Just an object
fun foo() {
val adHoc = object {
var x: Int = 0
var y: Int = 0
}
print(adHoc.x + adHoc.y)
}
But I am unable to understand the "Object expression with multiple supertypes specified" example given as below:
open class A(x: Int) {
public open val y: Int = x
}
interface B { ... }
val ab: A = object : A(1), B {
override val y = 15
}
What's happening here?
${ab.y} prints 15
but syntax -> ${ab.A.y} is not valid. My understanding of ${ab.A.y} it will print 1 :)
This line here:
val ab: A = object : A(1), B {
means that the class of ab is inherited from class A and implements interface B.
Actually the code example you gave will only compile if you declare and implement the interface. This is a possible implementation:
open class A(x: Int) {
public open val y: Int = x
}
interface B {
fun hi()
}
val ab: A = object : A(1), B {
override val y = 15
override fun hi() {
println("hi")
}
}
The expression ${ab.A.y} does not make much sense in this context, because the object ab does not have any field A. A is just the inherited superclass to which you could eventually cast.
It basically creates object ab with class type A with implementation of interface B.
So, let's say your class A has some method foo() & interface B has some method bar(), you can access them both on object ab as it's of class type A with implementation of B.
Hence, here you override variable y with value 15 meaning your superclass variable y will get overridden by value 15 from 1.

Kotlin: function delegation

I have a project that depends heavily on delegation and composition in Kotlin. Delegating properties is a breeze, but conceptually I'm not completely sure how to achieve delegation for functions in circumstances where the functions depend on other composed properties. I'd like to do something like this:
interface A {
val a: String
}
class AImpl: A {
override val a = "a"
}
interface B {
val b: String
}
class BImpl: B {
override val b = "b"
}
interface C<T> where T: A, T: B {
fun c() : String
}
class CImpl<T>(val ab: T) : C<T> where T: A, T: B {
override fun c() = ab.a + ab.b
}
// works
class ABC : A by AImpl(), B by BImpl()
// does not work
class ABC : A by AImpl(), B by BImpl(), C<ABC> by CImpl(this)
Of course, this type of thing would be achievable with the following:
interface A {
val a: String
}
class AImpl: A {
override val a = "a"
}
interface B {
val b: String
}
class BImpl: B {
override val b = "b"
}
interface C<T> where T: A, T: B {
fun c() : String
}
class CImpl<T>(val ab: T) : C<T> where T: A, T: B {
override fun c() = ab.a + ab.b
}
class AB : A by AImpl(), B by BImpl()
class ABC(ab: AB = AB(), c: C<AB> = CImpl<AB>(ab)) : A by ab, B by ab, C<AB> by c
but this feels clunky as it requires passing in objects for composition which bloats the size of the constructors - it would be cleaner for me to initialize the objects at the site of the class itself as they have no use outside of the class. Is there an elegant way to this with delegation and/or extensions?
You can make C extend A and B instead of passing to it a delegate. e.g.:
interface C : A, B {
fun c(): String
}
abstract class CImpl() : C {
abstract override val a: String
abstract override val b: String
override fun c(): String = a + b
}
class ABC : A by AImpl(), B by BImpl(), CImpl()
You can also do this with a default implementation in C without a CImpl:
interface C : A, B {
fun c(): String = a + b
}
class ABC : A by AImpl(), B by BImpl(), C
I don't think this is currently supported very well, but there's an issue that tracks this and related feature requests. (See Peter Niederwieser's comment on the issue.)

How to implement an abstract getter with property

I have java code:
public abstract class A {
abstract int getA()
}
I tried:
class B : A() {
val a = 0
}
Doesn't compile.
class B : A() {
override val a = 0
}
Still doesn't compile.
class B : A() {
override val a: Int get () = 1
}
Still doesn't compile.
class B : A() {
override val a: Int override get () = 1
}
Still doesn't compile.
class B : A() {
val a: Int override get () = 1
}
None of them are working. Does that mean I can only use
class B : A() {
override fun getA() = 1
}
? I think the last one(overriding the method) is ugly.
This could be worse when you have a getter-setter pair. It's expected to override getter-setter pair with a var property, but you have to write two methods.
According to #Miha_x64 ,
functions can be overriden only with a function.
Seems that I was trying something impossible.

Overriding same signature from different interfaces

in C sharp, if we have 2 interfaces, with the same signature method, we can implement them in one class, in the following way:
interface A
{
void doStuff();
}
interface B
{
void doStuff();
}
class Test : A, B
{
void A.doStuff()
{
Console.WriteLine("A");
}
void B.doStuff()
{
Console.WriteLine("A");
}
}
If we thranslate this to Kotlin we have
interface A
{
fun doStuff()
}
interface B
{
fun doStuff()
}
class Test : A, B
{
override fun doStuff() {
println("Same for A b")
}
}
fun main(args: Array<String>)
{
var test = Test();
test.doStuff() //will print Same for A b"
var InterfaceA:A = test
var InterfaceB:B = test
InterfaceA.doStuff()//will print Same for A b"
InterfaceB.doStuff()//will print Same for A b"
}
So, my question is, how can I
give to each interface a different implementation as in C sharp example?.
**Note: I have read the docs on https://kotlinlang.org/docs/reference/interfaces.html , there is a similar example,
interface A {
fun foo() { print("A") }
}
interface B {
fun foo() { print("B") }
}
class D : A, B {
override fun foo() {
super<A>.foo()
super<B>.foo()
}
}
Here, foo is implemented in each interface, so when implemented in D, it just call the implementation defined in the interface. But how can we give define different implementation in D?.
It is not possible in Kotlin. Kotlin is similar to Java in this respect. Methods that are override-equivalent in interfaces must have the same implementation in a class. The rationale behind that behavior is that casting a object reference to different types should not change behavior of its methods, e.g:
val test = Test()
(test as A).doStuff()
(test as B).doStuff() // should do the same as above