Class Delegation with `this` reference

Hi there,

I’m trying to design some interfaces that can be “plugged-in” platform-specific classes to leverage decoration and composability. However, I found a language barrier which I would like to discuss here. The following snippet is an example of what I am trying to accomplish:

class MyActivity: AppCompatActivity(), Toaster by ActivityToaster(this)

interface Toaster {
    fun toast(text: String, duration: Int) 
}

class ActivityToaster(private val activity: Activity) : Toaster {
    override fun toast(text: String, duration: Int) {
        Toast.makeText(activity, text, duration).show()
    }
}

However, the following is not allowed with the message:

‘this’ is not defined in this context

Looking at the generated bytecode, we get something similar to the following:

public final class ExampleActivity extends ComponentActivity implements ToastMaker {

   private final ActivityToastMaker $$delegate_0 = new ActivityToastMaker();

   // Other methods.
}

As you can see, this is available during the creation of the class delegation. Also, the following is completely valid syntax in Kotlin:

internal class ExampleActivity: ComponentActivity(), ToastMaker {

    private val toastMaker = ActivityToastMaker(activity = this)

    override fun makeToast(text: String, duration: Int) {
        toastMaker.makeToast(text, duration)
    }
}

I understand I could create the objects by myself and pass them around but it would be really nice to split the logic into small classes and compose them together using class delegation whenever necessary - that would allow me to use the activity as a ToastMaker for any API that receives it, reusing the abstractions I created.

That is very relevant in a world like Android where I do not control the instantiation of some classes and class delegation becomes hard to operate without a reference of this like the example above (e.g., you can’t pass constructor parameters and do by class)

Another example would be to use Pure DI by letting the compiler create all the boilerplate and leveraging Class Delegation with minimum effort, as for example:

internal class SharedContainer : 
        Feature1Module by MainFeature1Module(this), // depends on networking...
        Feature2Module by MainFeature2Module(this), // depends on networking...
        Feature3Module by MainFeature3Module(this), // *: See below!
        DomainModule by MainDomainModule(this),
        NetworkingModule by MainNetworkingModule(this)

// *: Could be combined with `where` keyword, to combine two or more modules.
internal class MainFeature3Module<T>(
       val dependencies: T
) : Feature3Module where T : NetworkingModule, T : DomainModule

I also understand there are some tricks points (for example, a delegated method that is called from the delegate class) but all of those already exist in Kotlin as you would end up in the same situation writing the class delegation manually…

Therefore, what am I missing here? Why isn’t that support in Kotlin?

2 Likes

Yeah, these restrictions regarding delegation are a little annoying to me as well. I understand this is probably to avoid working with partially uninitialized objects, but there is always such a risk, Kotlin can’t and doesn’t really fix it. Maybe I just don’t see a bigger problem here.

2 Likes