Why is it necessary to manually specifying the bin...
# kotlin-inject
f
Why is it necessary to manually specifying the binding between a class and the implemented interface? For example, I would expect the following code to work, but it fails instead
Copy code
interface Dependency

@Inject
class DependencyImpl : Dependency

@Component
abstract class MyComponent {
    abstract val dependency: Dependency
}
error
Copy code
Cannot find an @Inject constructor or provider for: myapp.test.Dependency
am I missing something? 🤔 thank you color
p
I am curious too. Doesn't Dagger work like that too. It forces you to specify the Binding implementation for a given interface in an abstract Module.
e
How else would the framework know which implementation to use?
p
Right, and the framework assumption is the moment it sees an interface, there is gonna be more than one implementer. Perhaps the framework could track these cases where there is only one implementer and not erroring out. But that would just add more confusion, inconsistency, and more likely performance consumption tracking this single ones implementations
e
Correct, it's much better to be consistent and explicit about this.
e
performance is the main reason. ksp works by starting at annotations and following references to types. There's no reference from your interface to it's implementation to follow. The alternative would be to scan your entire classpath which is a no-go
💡 1
f
What if we scan only the current module (or project)? Generating a
Map<[Interface], [Implementer @Inject class]>
should not be expensive in performance, or no? 🤔 My expectation is that 90% of the times the interface is going to have only one implementation in production, which can be overridden in tests. In such cases, auto-inferring the Implementation-Interface binding would save boilerplate code in the main source set. In case of multiple implementation (e.g. in the testing environment), then it would be easily detectable and would fallback to requiring explicit binding in the component. (e.g. If you override
Http
from the auto-inferred
RealHttp
to
TestHttp
)
p
Humm 🤔 perhaps adding another annotation like @SingleBinding
e
if you want to bind based on module you should look into the anvil solution(s). that's a better pattern for that imo
thank you color 1
r
This is exactly what kotlin-inject-anvil solves with the
@ContributesBinding
annotation https://github.com/amzn/kotlin-inject-anvil/
👌 3
Copy code
interface Dependency

@Inject
@ContributesBinding(AppScope::class)
class DependencyImpl : Dependency

@MergeComponent(AppScope::class)
abstract class MyComponent {
    abstract val dependency: Dependency
}
This should work now