Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementation for scoped components #416

Open
Al3xCalibur opened this issue Jul 21, 2024 · 7 comments
Open

Implementation for scoped components #416

Al3xCalibur opened this issue Jul 21, 2024 · 7 comments
Labels
question Further information is requested

Comments

@Al3xCalibur
Copy link

I was looking at the generated code today (the following example comes from the tests).
And I didn't completely get why it uses a LazyMap for ScopedComponent wheras I guessed a Lazy property was enough.
So I'm just interested to see the main idea, thanks!

public class InjectTypeAccessComponent() : TypeAccessComponent(), ScopedComponent {
  override val _scoped: LazyMap = LazyMap()

  override val string: String
    get() = _scoped.get("kotlin.String") {
      provideString()
    }

  override val `class`: IFoo
    get() = _scoped.get("me.tatarka.inject.test.IFoo") {
      provideClass()
    }
  // ...
}
@evant
Copy link
Owner

evant commented Jul 21, 2024

It's because you can have a scoped inject in a different module than the component so it can't know ahead of time every thing to create a property for. The map allows them to be created dynamically

@evant evant added the question Further information is requested label Jul 21, 2024
@Al3xCalibur
Copy link
Author

Oh, I see I'm adding an example from the tests to be sure

I see that the generated code is directly using the scoped LazyMap so it makes sense, it moves the creation closer to the usage (typically not in ExternalParent nor ExternalChild class, even if they define the bind)

To complete a bit the overall question, I wanted to define a scope of long-living services for my app and I thought it would be nice to avoid recreating it (typically for caches).
And I was expecting the implementation to be closer to the non-scoped one or closer to a manual DI (with components defining fields with eager or lazy values directly).
That's fine, thanks!

@Component
abstract class NestedExternalScopedComponent(@Component val parent: ExternalChildComponent) {
    abstract val foo: IExternalFoo // is defined in the parent: external child component
}

/* generated */
public class InjectNestedExternalScopedComponent(
  parent: ExternalChildComponent,
) : NestedExternalScopedComponent(parent) {
  override val foo: IExternalFoo
    get() = with(parent.parent) {
      (this as ScopedComponent)._scoped.get("me.tatarka.inject.test.module.ScopedExternalFoo") {
        ScopedExternalFoo()
      }.bind
    }
}

// and the parent.parent is
public class InjectExternalParentComponent() : ExternalParentComponent(), ScopedComponent {
  override val _scoped: LazyMap = LazyMap()
}

@Al3xCalibur
Copy link
Author

I checked the integration tests and I saw some benchmark
I was curious so I ran it, with an additional test of an eager version to see the maximum speed possible
I will probably push it (except if you think it is not needed)

@evant
Copy link
Owner

evant commented Jul 22, 2024

Yeah the benchmark was to see if there was a meaningful performance difference from using a map vs lazy prop, the result was there was not.

with an additional test of an eager version to see the maximum speed possible

Not sure what you mean by this?

@Al3xCalibur
Copy link
Author

I just have in mind the most basic class possible

class Example {
    val a: A = A() // instead of lazy { A() }
}

@evant
Copy link
Owner

evant commented Jul 23, 2024

That has different semantics though, being lazy is important for the expected behavior.

@Al3xCalibur
Copy link
Author

I agree, but still I think it can be interesting to measure

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

2 participants