-
-
Notifications
You must be signed in to change notification settings - Fork 727
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
map & set multibinding #1951
base: 4.1.0
Are you sure you want to change the base?
map & set multibinding #1951
Conversation
Looks interesting, will check for 4.1 👍 |
abd0d70
to
38e0173
Compare
UPDATE: module {
intoMap("keyOfComponent1") {
Simple.Component1() // implicitly declare Map<String, Simple.Component1>
}
intoMap("keyOfComponent2") {
Simple.Component2() // implicitly declare Map<String, Simple.Component2>
}
intoSet {
Simple.Component1() // implicitly declare Set<Simple.Component1>
}
intoSet {
Simple.Component2() // implicitly declare Set<Simple.Component2>
}
/* Map<String, Simple.Component1> & Map<String, Simple.Component2>,
Set<Simple.Component1> & Set<Simple.Component2> are different multibindings */
} so I update the implement. Now elements can only be injected through explicit multibinding declaration and force type safety: module {
declareMapMultibinding<String, Simple.ComponentInterface1> {
intoMap("keyOfComponent1") { Simple.Component1() }
intoMap("keyOfComponent2") { Simple.Component2() }
intoMap("keyOfComponent3") { Other() } // build error
}
declareSetMultibinding<Simple.ComponentInterface1> {
intoSet { Simple.Component1() }
intoSet { Simple.Component2() }
intoSet { Other() } // build error
}
} |
b81de19
to
b2cf278
Compare
…ify the corresponding elements
b2cf278
to
35407ae
Compare
The later element definition overrides the previous one, and the elements are iterated in the order they are defined.
The rare use cases: data class MapKey(
val name: String,
val value: Int,
) {
override fun toString(): String = name
}
module {
declareMapMultibinding<MapKey, Simple.ComponentInterface1> {
intoMap(MapKey("key", 1)) { Simple.Component1() }
intoMap(MapKey("key", 2)) { Simple.Component1() } // MapMultibindingKeyTypeException will be thrown
}
} since multibinding implement uses module {
declareMapMultibinding<MapKey, Simple.ComponentInterface1> {
intoMap(MapKey("key", 1)) { Simple.Component1() }
}
}
// declare in different modules
module {
declareMapMultibinding<MapKey, Simple.ComponentInterface1> {
intoMap(MapKey("key", 2)) { Simple.Component1() } // MapMultibindingKeyTypeException will be thrown
}
} |
…ys have different values but the same `toString()` representation.
eed67d0
to
62535ab
Compare
The multibinding overrides issue: module {
declareMapMultibinding<String, Simple.ComponentInterface1> {
intoMap("keyOfComponent1") { Simple.Component1() }
}
}
module {
declareMapMultibinding<String, Simple.ComponentInterface1> { // multibinding overrides
intoMap("keyOfComponent2") { Simple.Component2() }
}
} Generally, you can declare elements across modules, but here, multibinding overloads actually occur. However, these multiple multibinding declarations are essentially the same. |
An explanation of elements order with example: val module2 = module {
scope(scopeKey) {
declareMapMultibinding<Int, Simple.ComponentInterface1> {
intoMap(2) { Simple.Component1() }
}
}
}
val module1 = module {
scope(scopeKey) {
declareMapMultibinding<Int, Simple.ComponentInterface1> {
intoMap(1) { Simple.Component1() }
}
}
}
val module4 = module {
declareMapMultibinding<Int, Simple.ComponentInterface1> {
intoMap(4) { Simple.Component1() }
}
}
val module3 = module {
declareMapMultibinding<Int, Simple.ComponentInterface1> {
intoMap(3) { Simple.Component1() }
}
}
startKoin {
modules(module1, module2, module3, module4)
}
val map: Map<Int, Simple.ComponentInterface1> = scope.getMapMultibinding()
// in elements definition order, but linked scope (root scope) elements first then current scope elements
// module definition order is irrelevant, but module loading order is key.
map.keys.toList() == listOf(3, 4, 1, 2) It's not that I intentionally maintain the order, but this order is crucial for element overloading. For example: val component = Simple.Component1()
val module44 = module {
declareMapMultibinding<Int, Simple.ComponentInterface1> {
intoMap(4) { component }
}
}
modules(module1, module2, module3, module4, module44)
map[4] === component // later element definition wins |
d1d85aa
to
fede627
Compare
@luozejiaqun it's a great proposal, I would like to review naming/API to propose something more compact. I opened KFIP https://github.com/InsertKoinIO/KFIP/ to open design process to public. This could be a good first proposal that we can design together. I can start a draft and we can work together on this Map/Set injection feature. We can talk also on #koin-contributors channel |
@arnaudgiuliani I'm looking forward to talking more about this with you, and I do have a few questions. I tried making a PR on KFIP, but writing so much English technical documentation is a little difficult for me. |
Let me bootstrap it, this should frame our discussion around 👍 |
Implement map & set multibinding just like dagger2.
Here is some implementation details:
Every MapMultibinding & SetMultibinding will involve 3 definitions:
When getting specific element from map multibinding, the map multibinding will try to retrieve the element through multibindingValueQualifier;
When getting all elements from map or set multibinding, the multibinding will first try to get all MultibindingIterateKeys and filter them based on multibindingQualifier, and then retrieve each element through multibindingElementQualifier.
The known problems:
the elements order of multibiding is different with the order of element definitionsNow, both set & map multibinding elements are iterated in the order they are defined.And just like dagger2, multibinding is inherited (because MultibindingIterateKey can be retrieved from getAll), current scope's multibinding can get all elements that define in linked scope.
Here are some use cases:
issue #772