Giter VIP home page Giter VIP logo

Comments (6)

evant avatar evant commented on June 3, 2024

As a work-around you can return a Deferred object

@Component
@NetworkScope
internal abstract class NetworkComponent(
    @get:Provides protected val apiInstanceCounter: AtomicInteger,
    @get:Provides val scope: CoroutineScope,
) {
    @NetworkScope
    abstract fun api(): Deferred<Api>

    @Provides
    @NetworkScope
    protected fun api(service: Service, scope: CoroutineScope): Deferred<Api> =
        scope.async(start = CoroutineStart.LAZY) { service.connect() }

    protected val DummyNetworkService.bind: Service
        @Provides get() = this
}

interface Api

interface Service {
    suspend fun connect(): Api
}

@Inject
class DummyNetworkService(private val apiInstanceCounter: AtomicInteger) : Service {
    override suspend fun connect(): Api {
        apiInstanceCounter.incrementAndGet()

        return object : Api {}
    }
}

internal class KotlinInjectTest {
    @Test
    fun `calling scoped suspending provider should create singleton instance`() {
        val apiInstanceCounter = AtomicInteger(0)


        runBlocking {
            val networkComponent = NetworkComponent::class.create(apiInstanceCounter, this)
            val apiInstance0 = networkComponent.api().await()
            val apiInstance1 = networkComponent.api().await()

            assertEquals(apiInstance0, apiInstance1)
        }
    }
}

from kotlin-inject.

evant avatar evant commented on June 3, 2024

Marking as a bug because at the very least it should have a good error message. Will look into if this can be supported

from kotlin-inject.

sdipendra avatar sdipendra commented on June 3, 2024

Thanks for looking into it. It'll be great if this can be supported.
My project currently uses Dagger(kotlin jvm) with Deferred as you have suggested. Using Deferred causes all the dependent objects to also return Deferred, which requires boiler plate code for launching the async, awaiting deferred value in deferred provider methods & passing the coroutineScope to the component.
Even with Deferred "kotlin-inject" is better option than Dagger as it will only require Deferred at the point of "suspending provider" call & dependent object relationship can be expressed without Deferred by adding a suspend mapping from Deferred value to value using await().

    @Provides
    protected suspend fun api(deferredApi: Deferred<Api>): Api = deferredApi.await()

And then api can be returned/injected directly instead of Deferred:

    @NetworkScope
    abstract suspend fun api(): Api

Since it's technically possible with hand written code, it probably should be possible with code generation.

On seeing the location of the error, the problem seems to be in the init block of the get method of LazyMap:

    actual fun <T> get(key: String, init: () -> T): T

Maybe a suspending variant could help:

    actual suspend fun <T> get(key: String, init: suspend () -> T): T

from kotlin-inject.

evant avatar evant commented on June 3, 2024

yeah, though it looks like kotlinx.coroutines is required to implement the suspend version, which isn't currently a dependency. Will have to figure out how to make that optional or if we can live with the extra dependency.

from kotlin-inject.

evant avatar evant commented on June 3, 2024

note: looked into this more and you really need a coroutine-aware lock for this to work correctly, this means that either coroutines would have to be a hard-dependency or we'd need actually do different code gen based on a flag or something. both options feel kinda gross 😞

from kotlin-inject.

sdipendra avatar sdipendra commented on June 3, 2024

This is not blocking for my usecase, and is a good to have feature.
The delta utility vs amount of effort required to implement/maintain it doesn't seems worth it.
Providing an error message with the workaround steps should be good enough.

from kotlin-inject.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.