Scopes & lifecycles
Inara has no notion of scope.
It does not need one: a scope is simply a module instance.
A single lives exactly as long as the module that holds it, so the lifetime of a value is the lifetime of the module you built it in.
One module per lifetime
Group members by how long they should live:
-
an application module, built once at startup, for everything that lives as long as the application;
-
a session module, built when a user logs in and dropped when they log out;
-
a screen or request module, built for one screen or one request.
Each shorter-lived module composes the longer-lived one, so it can use its members without rebinding them.
@DIModule
interface AppModule {
fun httpClient(): HttpClient
fun database(): Database
}
@DIModule(composed = true)
interface SessionModule : AppModule {
val user: User
fun repository(): UserRepository
}
val app = AppModule( (1)
httpClient = Binding.single { HttpClient() },
database = Binding.single { Database.open() },
)
fun onLogin(user: User): SessionModule = SessionModule( (2)
appModule = app,
user = Binding.value(user),
repository = Binding.single { UserRepository(httpClient(), database(), user) }, (3)
)
| 1 | Built once, at startup. |
| 2 | Built at every login. |
| 3 | One repository per session, which reads members of both modules. |
The session module reuses the bindings of the application module as they are: httpClient() returns the very same instance in every session.
When the session module is no longer referenced, its own single instances are garbage collected with it, while the application module keeps its own.
Lifecycles within a module
Within a module, the binding of each member decides its lifecycle:
| Lifetime | Binding |
|---|---|
the module |
|
as long as something uses it |
|
one per argument value, for the module |
|
none: a new instance every time |
|
See Bindings for each of them.
Building classes in a scope
@DIFactory builds classes from whichever module you give it.
A factory from the session module builds a class that can depend on members of both the session and the application:
class ProfileViewModel(val user: User, val repository: UserRepository)
@DIFactory(builds = ProfileViewModel::class, from = SessionModule::class)
object ProfileViewModelFactory
val viewModel = ProfileViewModelFactory.ProfileViewModel(session)
Values that only exist for one call, like a route or a request, are passed as with arguments rather than stored in a module.