Let components know their containing scope
Considering I have 2 components in root scope :
graph LR
subgraph ROOT SCOPE
COMP5 ...->|by inject| COMP6
end
class COMP5 { val comp6 by inject<COMP6>() }
Any other component can use them by basic injection, even from a scoped component :
graph LR
subgraph "ROOT SCOPE"
COMP0 ....->|by inject| COMP5
COMP5 ...->|by inject| COMP6
COMP1
end
subgraph "SCOPE<COMP1>"
COMP1_SCOPE([SCOPE])
COMP2
COMP1_SCOPE --->|defines| COMP2
end
COMP1 -->|creates| COMP1_SCOPE
COMP1 ..->|by inject| COMP2
COMP2 ..->|by inject| COMP5
module {
single { COMP0() }
single { COMP1() }
single { COMP5() }
single { COMP6() }
scope<COMP1> {
scoped { COMP2() }
}
}
BUT if I want a custom COMP6 for 1 particular component I need to scope it and all components before him in the chain :
graph LR
subgraph "ROOT SCOPE"
COMP5["COMP5("GLOBAL")"]
COMP6["COMP6("GLOBAL")"]
COMP0 ....->|by inject| COMP5
COMP5 ...->|by inject| COMP6
COMP1
COMP3
end
subgraph "SCOPE<COMP1>"
COMP1_SCOPE([SCOPE])
COMP2
COMP1_SCOPE -->|defines| COMP2
end
subgraph "SCOPE<COMP3>"
COMP3_SCOPE([SCOPE])
COMP4
SCOPED_COMP5["COMP5("CUSTOM")"]
SCOPED_COMP6["COMP6("CUSTOM")"]
COMP3_SCOPE --->|defines| COMP4 & SCOPED_COMP5 & SCOPED_COMP6
COMP4 ...->|by inject| SCOPED_COMP5
SCOPED_COMP5 ..->|by inject| SCOPED_COMP6
end
COMP1 --->|creates| COMP1_SCOPE
COMP1 ..->|by inject| COMP2
COMP2 ..->|by inject| COMP5
COMP3 --->|creates| COMP3_SCOPE
COMP3 ..->|by inject| COMP4
But for that, all those components have to know their containing scope. This is not a scope they create, it's the scope who created them (and in fact, if they create their own scope, shouldn't it be linked to the containing scope ?).
graph LR
subgraph "SCOPE<COMP3>"
COMP3_SCOPE([SCOPE])
COMP4
SCOPED_COMP5["COMP5("CUSTOM")"]
SCOPED_COMP6["COMP6("CUSTOM")"]
COMP3_SCOPE --->|defines| COMP4 & SCOPED_COMP5 & SCOPED_COMP6
COMP4 & SCOPED_COMP5 & SCOPED_COMP6 --->|knows| COMP3_SCOPE
COMP4 ...->|by inject| SCOPED_COMP5
SCOPED_COMP5 ..->|by inject| SCOPED_COMP6
end
COMP3 --->|creates| COMP3_SCOPE
COMP3 ..->|by inject| COMP4
module {
single { COMP0() }
single { COMP1() }
single { COMP3() }
single { COMP5("GLOBAL") }
single { COMP6("GLOBAL") }
scope<COMP1> {
scoped { COMP2() }
}
scope<COMP3> {
scoped { COMP4(scope = this) }
scoped { COMP5("CUSTOM", scope = this) }
scoped { COMP6("CUSTOM", scope = this) }
}
}
For now, the only way to know its containing scope is to pass it to the constructor but constructor injection is tedious when abstract classes are involved because all params have to be copied.
It could be nice to have the possibility to inject this containing scope :
-
Either with an interface like
interface Scoped { var container : Scope? }which is automatically called after instantiation. (the scope should remain nullable because a component could exist in and out a scope, or let us access root scope) -
or via a method like
val container = instantiatingScope()we could use in components during init phase, which could eventually be done with a ThreadLocal trick wrapping the definition execution, like :
val CURRENT_SKOPE = ThreadLocal<Skope>()
inline fun <reified T> ScopeDSL.skoped(
qualifier: Qualifier? = null,
noinline definition: Definition<T>
) = scoped(qualifier) { params ->
val current = CURRENT_SKOPE.get()
CURRENT_SKOPE.set(this)
try {
definition(params)
} finally {
CURRENT_SKOPE.set(current)
}
}
fun KoinScopeComponent.instantiatingScopeOrRoot() =
CURRENT_SKOPE.get() ?: getKoin().getScope("_root_")
fun KoinScopeComponent.requireInstantiatingScope() = CURRENT_SKOPE.get()
?: throw IllegalStateException("use skoped() to declare ${javaClass.simpleName}")
fun KoinScopeComponent.instantiatingSkope(): Skope? = CURRENT_SKOPE.get()
Parking your proposal in 4.0.0 for further new scope improvements 👍
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.