Lazy class delegate in Kotlin?
Asked Answered
R

1

7

I'm trying to do a Facade of my interfaces to abstract real types and omit need to name all of them directly. I ended up with this:

class Facade : ILeft by LeftImpl(), IRight by RightImpl()

ILeft and IRight are interfaces and I instantiate their implementations. This is in general solution I was looking for and it worked.

BUT

Let's say, I know, I will use most of the time only ILeft, or IRight. There are cases where I use them both, but most of the time, I'll use just one. Thus I would like to make them lazy, but how?

1) It's possible to use instance provided in the constructor, but that requires an instance.

2) If I try to define:

class Facade : ILeft by left, IRight by right {
     val left by lazy { LeftImpl() }
     val right by lazy { RightImpl() }
}

The left and right are inaccessible in the class declaration.

I can make the implementations lazy inside, that's also a possibility. But I'm trying to find a way, to write this out of the box, just by kotlin.

Any ideas how to have Facade object with just ILeft actually initialized by implementation?

Reptile answered 16/8, 2018 at 12:55 Comment(0)
A
6

Kotlin does not currently support implementing interfaces by delegating them to properties (KT-83), only constructor parameters can be used in expressions used in delegation, and these expressions are always evaluated at construction time.

So, indeed, you will likely need to define lazy proxy implementations for the interfaces:

class ILeftLazy(lazyLeft: Lazy<ILeft>): ILeft {
    private val left by lazyLeft

    override fun someLeftFun(): Foo = left.someLeftFun()
    /* ... */
}

Then you can rewrite the Facade primary constructor to accept Lazy instances and implement the interfaces by delegation to the implementations:

class Facade(
    lazyLeft: Lazy<ILeft>
    lazyRight: Lazy<IRight>
) : ILeft by ILeftLazy(lazyLeft), IRight by IRightLazy(lazyRight) {
    val left by lazyLeft
    val right by lazyRight
}

You can then make the primary constructor private and provide a no-arg secondary constructor that passes lazy { ILeftImpl() } and lazy { IRightImpl() } to the primary one.

This requires some boilerplate implementing the lazy proxy implementations but still allows you to implement the interfaces in Facade by delegation.

Anxious answered 16/8, 2018 at 13:14 Comment(2)
Assuming I used this for SharedPreferences in Android, the lazy proxy would double the code, since my ILeft and IRight are already proxies over SharedPrefs. Anyway, what is the meaning of left and right in the second fragment?Reptile
@l0v3, I kept the left and right properties in case you want to expose them as a part of the Facade's API, just to show that you can delegate them to the same lazyLeft and lazyRight. They are not needed for anything specifically.Anxious

© 2022 - 2024 — McMap. All rights reserved.