kotlin-inject
kotlin-inject copied to clipboard
Add default values for component constructor arguments which are components with no constructor arguments
Example Code:
@Component abstract class NoArgComponent {
@get:Provides val string: String = "Hi"
}
@Component abstract class MyComponent(@Component component: NoArgComponent)
Generates:
InjectMyComponent(component: NoArgComponent = InjectNoArgComponent()) : MyComponent(component)
This feature provides functionality similar to how dagger can build modules which don't have any constructor params.
Interesting idea! One thing to note is that I'm leaning towards suggesting to use inheritance for combining things like you would with modules whereas component dependencies would be used when you have multiple different component lifetimes. So in your case you'd do:
interface NoArgComponent {
@get:Provides val string: String get() = "Hi"
}
@Component abstract class MyComponent : NoArgComponent
If you use separate components for different lifetimes then it doesn't make sense to have it as a default parameter since you'd want to hold a reference to it separately. However, there may be some limitations to this approach so there may be cases where your suggestion is useful, haven't figured that out yet.
One thing is default values you declare should probably be propagated, so you could do:
@Component abstract class MyComponent(@Component component: NoArgComponent = NoArgComponent())
MyComponent::class.create()
at least
One thing is default values you declare should probably be propagated, so you could do:
@Component abstract class MyComponent(@Component component: NoArgComponent = NoArgComponent()) MyComponent::class.create()
at least
Yea this feature is also a good addition, I tried doing this once already and realized it didn't support that yet.
I think the main limitation of component extension is it leaks the types of the "module" into the components public definition:
class OkHttpClient
@Inject class MyApi(private val myApiClient: OkHttpClient)
@Component interface HttpClient {
@get:Provides val client: OkHttpClient get() = OkHttpClient()
}
@Component abstract class ApiComponent : HttpClient {
@get:Provides abstract val api: MyApi
}
fun test() {
ApiComponent::api
ApiComponent::client
}
In this example I don't really want the client to be accessible from the api component just the final api type.
Yep that's certainly a limitation. If you could make methods on interfaces protected that would fix this, but alas you can't. One option would be to have a separate 'public api' interface, but I'm not sure I like that.
interface ApiComponent {
val api: Api
}
@Component abstract class ApiComponentImpl : ApiComponent, HttpClient
val component: ApiComponent = ApiComonentImpl::class.create()
Just merged in support for omitting default args, I'm hopping this will be enough, but we can revisit if there is a good reason to.
Closing with the assumption the current implementation is good enough