Trying to use interface delegation and I found mys...
# getting-started
s
Trying to use interface delegation and I found myself in a situation where I am not sure about if what I am trying to do is possible. More in thread 🧵
The use case is that I want to have a single entry point for all the call sites to be able to access a
FeatureManager
which could provide all the various stuff that may be coming from different sources. I had some code that looks something like this (implementation details removed for brevity)
Copy code
interface FeatureFlagProvider
interface LoginMethodProvider
interface FooProvider

class FeatureManager(
    featureFlagProvider: FeatureFlagProvider,
    loginMethodProvider: LoginMethodProvider,
    fooProvider: FooProvider,
) : FeatureFlagProvider by featureFlagProvider,
    LoginMethodProvider by loginMethodProvider,
    FooProvider by fooProvider
Which does what I want I think, I can inject this and have access to all the features I want. I wanted to then try to make
FeatureManager
an interface instead (maybe I wouldn’t need to, since I can just fake all the providers instead in tests I guess, but at this point I am just curious for the feasibility of it, or if I am going down a weird path.) Something like this
Copy code
interface FeatureManager : FeatureFlagProvider, LoginMethodProvider, FooProvider
But then if I were make an imlpementation of it like this
class FeatureManagerImpl : FeatureManager
I don’t see how I could achieve the same delegation behavior 🤔 This doesn’t work
Copy code
class FeatureManagerImpl(
    featureFlagProvider: FeatureFlagProvider,
    loginMethodProvider: LoginMethodProvider,
    fooProvider: FooProvider,
) : FeatureManager by ???
And if I make it receive a FeatureManager directlty
class FeatureManagerImpl(featureManager: FeatureManager) : FeatureManager by featureManager
I don’t see a simple way to create this instance without actually implementing all the funtions and deferring to the appropriate interface instead of doing this convenient
by
delegation. Something like
Copy code
val someFeatureFlagProviderImpl: FeatureFlagProvider = TODO()
val someLoginMethodProviderImpl: LoginMethodProvider = TODO()
val someFooProviderImpl: FooProvider = TODO()
val fm = FeatureManagerImpl(
    object : FeatureManager {
        override fun featureFlagProviderProvide() {
            someFeatureFlagProviderImpl.featureFlagProviderProvide()
        }

        override fun loginMethodProviderProvide() {
            someLoginMethodProviderImpl.loginMethodProviderProvide()
        }

        override fun fooProviderProvide() {
            someFooProviderImpl.fooProviderProvide()
        }
    }
)
This is the first time I actually am playing around with this language feature, so this is mostly so I understand it better I guess, but any pointers if what I am trying to do is weird/useless/whatever would be great. In the end I think I will just go with the class implementation which seems to work alright if I can’t make this work.
e
Copy code
class FeatureManagerImpl(
    featureFlagProvider: FeatureFlagProvider,
    loginMethodProvider: LoginMethodProvider,
    fooProvider: FooProvider,
) : FeatureManager,
    FeatureFlagProvider by featureFlagProvider,
    LoginMethodProvider by loginMethodProvider,
    FooProvider by fooProvider
🙌 1
s
Right, this does seem to work actually! The syntax is a bit weird or is it just me? I’m having a bit of a hard time wrapping my head around this. When we’re now calling those functions, we’re actually deferring to the implementations as we should, but we’re also implementing
FeatureManager
which allows us to use it as an object of that type as well. And I see that if I remove one of the
by
or if I remove that entire line so that it doesn’t implement that interface, then it does correctly prompt me to implement that one interface. Feels a bit like magic to me but it works 😅 Definitely didn’t think I’d come up with this syntax myself, and I feel like I haven’t seen almost anyone using this
by
syntax in the wild for implementing interfaces. Thank you a lot for helping out!
e
I use it all the time! And the way it makes sense to me is I view the interfaces as additive contracts and delegation as fulfilling a part of the combined contract.
s
Yeah the more I look at it and with what you said now the more it makes sense! Honestly I was expecting this question to go unanswered but you came in and saved the day 😅 Thanks again!
🙌🏼 1
🦜 1
🙌 1