koin icon indicating copy to clipboard operation
koin copied to clipboard

Simplify binding of interface to a concrete implementation using Extended DSL

Open igorwojda opened this issue 2 years ago • 1 comments

Is your feature request related to a problem? Please describe. Define an instance of the parametrized class using

In koin 3.2.0 it is possible to bind an interface to concrete implementation like this: single<AlbumRepository> { AlbumRepositoryImpl(get(), get()) }

Describe the solution you'd like I wonder if type Kotlin type system would allow simplifying the above syntax to... singleOf<AlbumRepository>(::AlbumRepositoryImpl) ...so there is no need to explicitly pass params

This is reified version of what is already possible:

single { GetAlbumUseCase(get()) }
    
singleOf(::GetAlbumUseCase) // no need to explicitly pass params

Target Koin project https://github.com/igorwojda/android-showcase

igorwojda avatar Aug 26 '22 11:08 igorwojda

Hello,

yes. I will check to help make it better and allow kind of writing as you mention 👍

arnaudgiuliani avatar Aug 29 '22 13:08 arnaudgiuliani

@igorwojda The API already allows such direct binding:

val koin = koinApplication {
    modules(module {
        singleOf<IClassA>(::ClassA)
    })
}.koin
assertNotNull(koin.getOrNull<IClassA>())
assertNull(koin.getOrNull<ClassA>())

This is working, but keep in mind that it can't block some configuration checks. The new verify() API allows checking Koin configuration statically by looking at class constructors. In such "direct binding," we don't know the original class to build from the external point of view.

There is always pros and cons in each part

arnaudgiuliani avatar Dec 13 '22 09:12 arnaudgiuliani

I can't make this work. At least not with a real life example. As soon as my class has a dependency I get: "None of the following functions can be called with the arguments supplied." and it does not compile anymore. Minimal example:

class ClassA
interface IClassB
class ClassB(private val classA: ClassA): IClassB

val myModule = module {
    singleOf(::ClassA)
    singleOf<IClassB>(::ClassB)  // <-- This line fails with the above-mentioned error
}

Is there a way to resolve this or do I have to use the old-style dsl?

chennemann avatar May 12 '23 12:05 chennemann

I am having the same problem, please reopen.

geworfener avatar Aug 18 '23 09:08 geworfener

same as https://github.com/InsertKoinIO/koin/issues/1598 it's not intended to use the inferred type in "constructor dsl", singleOf, factoryOf ...

You need to use the bind operator like this:

val myModule = module {
    singleOf(::ClassA)
    singleOf(::ClassB){ bind<IClassB>() }
}

arnaudgiuliani avatar Aug 29 '23 13:08 arnaudgiuliani

Hello @arnaudgiuliani , Why not add this possibility to "constructor DSL" so as not to record ClassB and IClassB in the module which is not a good practice when using interfaces.

DSL extensions might look like this:

inline fun <reified IR: Any, reified R : IR, reified T1> Module.factoryOf(
    inferredType: KClass<IR>,
    crossinline constructor: (T1) -> R,
    noinline options: DefinitionOptions<IR>? = null
): KoinDefinition<IR> = factory<IR> { new(constructor) }.onOptions(options)

Thanks in advance for you rsponse.

dbaronne avatar Sep 28 '23 13:09 dbaronne

@dbaronne yes, interesting. Need to check how it's possible and how it's interacting with the current DSL

arnaudgiuliani avatar Oct 31 '23 07:10 arnaudgiuliani