question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Feature request: Scope-private bindings

See original GitHub issue

Some bindings are meant to be injected only in the scope in which they are defined, such that injecting them in a subscope is a logical bug. For example, let’s say that I add a Closer binding to my application scope to allow objects to register for cleanup. If an object belonging to a strict subscope of the application scope were to use this Closer, it would get leaked until application cleanup. In the Android world, a Lifecycle object in an activity scope would cause objects in strict subscopes to leak until activity destruction if they were to add themselves as observers.

I’ve seen this issue numerous times with objects that are essentially event dispatchers: release notifiers, lifecycle event dispatchers, save state handlers… We typically deal with them by qualifying them with a @WithMatchingScope(SCOPE_NAME) annotation, and using static analysis to detect injection in the wrong scopes. However, this is just adding extra boilerplate to work around the core problem: the binding should just not be visible at all outside of the scope for which it’s intended. It would be ideal if Dagger allowed annotating such bindings with a marker such as @Private and enforced the contract.

One nice side effect of using scope-private bindings is that nested subcomponents would be able to declare their own instances of each binding without the extra qualification. For example, I’d like to be able to add Closers to all my scopes without concern for clashes, since each Closer is meant to be used only within its own scope. And, more importantly, I’d be able to use Closer without the extra qualification in the injected constructor of my unscoped objects, and get the right instance of the Closer based on the instantiation scope. This would be a critical piece of an implementation of a generic component cleanup mechanism in Dagger.

Issue Analytics

  • State:open
  • Created 5 years ago
  • Reactions:1
  • Comments:7 (2 by maintainers)

github_iconTop GitHub Comments

1reaction
cesar1000commented, Mar 11, 2019

I think that this kind of feature would be particularly useful on Android, since it uses very strict lifecycles in multiple nested scopes, but has general value in any applications that implement a concept of lifecycle or component-scoped event dispatcher.

The alternatives that you suggest are workable, but they require central coordination. Also, they don’t prevent registration of an object in a Closer (or other type of event dispatcher) in the wrong scope. Also, it couples component definitions to specific scopes. For example let’s say that I define this:

class MyViewController {
  @Inject
  MyViewController(Lifecycle lifecycle) {
    lifecycle.registerObserver(event -> { ... })
  }
}

Ideally, I’d like to be able to inject MyViewController in any scope, and let dagger figure out with Lifecycle is available within that particular scope. Using a qualifier like, say, @FeatureXScope would tie this component to that scope and hinder reuse.

In the case of unscoped bindings, I would think that every unscoped injection can ultimately be traced back to a particular component. You’re likely already doing that to determine which scoped bindings are available for injection into an unscoped binding, right?

0reactions
trevjonezcommented, Dec 12, 2021

It would seem there is other “high impact” projects leaning heavily on the concept of a scope local or override mechanism.

https://developer.android.com/jetpack/compose/compositionlocal

Read more comments on GitHub >

github_iconTop Results From Across the Web

An Introduction to Scoped Bindings in SpecFlow
One nice aspect of SpecFlow is the ability to scope bindings by feature title, scenario title, or tag. Normally bindings are global to...
Read more >
Binding as Sets of Scopes - CS @ Utah
Roughly, every binding form and macro expansion creates a scope, and each fragment of syntax acquires a set of scopes that determines binding...
Read more >
Contexts and Dependency Injection - Quarkus
A package-private constructor injection. @Inject is optional in this particular case. 3. Supported Features. Programming model.
Read more >
Set scope of all bindings after loading a Ninject module
In the MVC app, I would like to use the InRequestScope scope binding, but in another application (that references my core assemblies where ......
Read more >
The dangers and gotchas of using scoped services in ...
Each request gets a new scope, so the Scoped services are isolated from one another. Singleton and scoped service resolution in ASP.NET Core...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found