-
-
Notifications
You must be signed in to change notification settings - Fork 178
Description
Description:
Currently, LazyInjected<T> can't be used inside a struct unless the entire struct is marked as mutating whenever the wrapped value is accessed. This severely limits its usability in value-type contexts, especially in SwiftUI views or other immutable setups where mutation isn't desired or even possible (e.g., inside let constants or non-mutating closures).
The issue stems from the wrappedValue implementation, which is declared as mutating get. While lazy initialization inherently implies mutation of internal state, it’s possible to work around this in Swift by using reference types internally (e.g., a private class holder) to manage the lazy resolution without requiring the outer wrapper to be mutating.
Proposed solution
Refactor LazyInjected to store its state (like dependency and initialize) in a separate reference-type container (e.g., LazyStorage<T>). This would allow wrappedValue to be non-mutating from the consumer’s perspective while still enabling lazy resolution under the hood.
This pattern is already used by other property wrappers in the Swift ecosystem (e.g., @StateObject in SwiftUI) and would preserve the current API while greatly expanding compatibility.
Current limitation example
struct MyView {
@LazyInjected(\.myService) private var service // ❌ Can't use without mutating context
}This forces awkward workarounds or prevents adoption in pure value-type architectures.
Benefits
- Enables use of
LazyInjectedinstructs without requiringmutatingmethods. - Maintains lazy, on-demand resolution semantics.
- Keeps backward compatibility if implemented carefully.
Would you be open to a PR implementing this approach?