Skip to content
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

Define priority on components #1652

Open
1 task done
manuelleduc opened this issue Nov 27, 2024 · 5 comments
Open
1 task done

Define priority on components #1652

manuelleduc opened this issue Nov 27, 2024 · 5 comments
Assignees

Comments

@manuelleduc
Copy link

Is there an existing proposal similar to this?

  • I have searched the existing proposals

What are you proposing?

Usually, when several components are registered with the same service identifier and the same tags/name, there is conflict for ambiguity during components resolution.
What I propose it to introduce the notion of priority as an integer value.
In case of ambiguity, the component with the highest priority is returned during resolution.

Is there any specific group of users that will benefit from this?

As a developer of open ecosystems based on extension, this mechanism is useful in use cases where we need an extension to override a "default" component.
Here, by defining an equivalent component, but with a higer priority.

What problems are you trying to solve?

This is useful in case of open extensibility, where not all extensions are known at development time.

Do you have any references or examples that can illustrate your idea?

This is a mechanism that is quite common on server side dependency injection. I'm coming from a Java development background where this priority mechanism is of great help.

What type of idea is this?

Improvement of existing idea: Similar idea exists but this is an improvement

@notaphplover
Copy link
Member

Hey @manuelleduc, what would be the behavior with multiple injection? I understand multiple injected bindings wouldn't be affected by priorities, is that so?

@manuelleduc
Copy link
Author

Hey @manuelleduc, what would be the behavior with multiple injection? I understand multiple injected bindings wouldn't be affected by priorities, is that so?

Let say we have the following components registered:

  • DefaultComponentA name=CA, priority=1000
  • DefaultComponentB name=CB, priority=1000
  • SpecialComponentA name=CA, priority=500 (500 is a "higher" priority than 1000)

In case of multiple injection, a single component for each name is returned, so the resulting array would be: [DefaultComponentB , SpecialComponentA].
DefaultComponentB has no ambiguity, and SpecialComponentA has a name conflict with DefaultComponentA, but the conflict is resolved by using the component with the highest priority.

I hope this makes what I have in mind clearer.

@notaphplover
Copy link
Member

I see. Your proposal makes a lot of sense. Unfortunatelly, being totally honest with you, the current priorities are:

  1. Fixing bugs. It's been a while since someone takes care of the library, and ensuring bugs are properly addressed is a must.
  2. Internal refactors. It's time for the library to improve the internal design so it's more maintainable. Improving internal types, data structures and even algorighms is an important task to confidently release new versions of the library, fix wrong behavior in edge cases and implement features like this one without adding too much technical debt.
  3. Adding features. I want to provide new features to the library so users have a better experience with the library.

If this feature was simple to implement, I would gladly go for it in december. But I'm afraid it's not really the case (mostly due to existing technical debt). I'm willing to implement this feature in the long term, but it won't be implemented soon :(

@manuelleduc
Copy link
Author

I see. Your proposal makes a lot of sense. Unfortunatelly, being totally honest with you, the current priorities are:

1. Fixing bugs. It's been a while since someone takes care of the library, and ensuring bugs are properly addressed is a must.

2. Internal refactors. It's time for the library to improve the internal design so it's more maintainable. Improving internal types, data structures and even algorighms is an important task to confidently release new versions of the library, fix wrong behavior in edge cases and implement features like this one without adding too much technical debt.

3. Adding features. I want to provide new features to the library so users have a better experience with the library.

If this feature was simple to implement, I would gladly go for it in december. But I'm afraid it's not really the case (mostly due to existing technical debt). I'm willing to implement this feature in the long term, but it won't be implemented soon :(

Sure, thanks a lot for you answer.
I think I can have a temporary solution by keeping track of components priorities outside Inversify, and load/unload components when needed. But, having this concept natively supported would of course make things easier.
In the meantime, I must say I'm happy to see the project being actively maintained again, kudos for that.

@notaphplover
Copy link
Member

I think I can have a temporary solution by keeping track of components priorities outside Inversify, and load/unload components when needed. But, having this concept natively supported would of course make things easier.

Yeah, I've been trying to think about a generic workaround about this. You might express priorities with tags / names and inject both the default service and the prioritized one. If the prioritized one exist you would not use the default one:

@injectable()
class PrioritizedServiceWrapper<TService> {
  pulic readonly service: TService;

  constructor(
    @tagged('priority', 'low')
    @inject('service-id')
    @optional()
    lowPrioritizedService: TService | undefined,
    @tagged('priority', 'medium')
    @inject('service-id')
    @optional()
    mediumPrioritizedService: TService | undefined,
    @tagged('priority', 'high')
    @inject('service-id')
    @optional()
    highPrioritizedService: TService | undefined,
    @inject('service-id')
    service: TService,
  ) {
    this.service = highPrioritizedService ?? mediumPrioritizedService ?? lowPrioritizedService ?? service;
  }
}

This idea looks sort of ugly, but you could probably make an abstraction around this.

In the meantime, I must say I'm happy to see the project being actively maintained again, kudos for that.

Thank you so much 😃

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants