Skip to content

Populate a map by combining name and group attributes #1036

@jquirke

Description

@jquirke

Currently FX supports injecting multiple different implementations of an interface type using groups
https://pkg.go.dev/go.uber.org/fx#hdr-Value_Groups

This allows me to Provide multiple implementations of an interface Foo provided they are annotated with group, and collect them

type Params struct {
   fx.In

   Foos []Foo `group:"myfoos"`

where a particular Foo can be provided as

type Out struct {
   fx.Out
   
   Foo `group:"myfoos"`

However, the Foos I received back are not able to be identified by name.

Describe the solution you'd like

I would like to be able to populate a map of named foos, using the existing name annnotation:

type Params struct {
   fx.In

   Foos map[string]Foo `group:"myfoos"`

where a particular Foo can be provided as

type Out struct {
   fx.Out
   
   Foo1 Foo `name:"foo1" group:"myfoos"`
   Foo2 Foo `name:"foo2" group:"myfoos"`

This allows me a powerful capability: To name and group a type together, and obtain it as an unordered slice, a single instance by name, or as a map of names to instances.

Describe alternatives you've considered

A trivial solution is to extend Foo to include a Name() method, and then simply organise this into a map[string]Foo.

foos := make(map[string]Foo)
for _, foo := range params.Foos {
    foos[foo.Name()] = foo
}

But there are many cases where components need to be looked up by name according to dynamic configuration, that re-implementing this for each case seems inelegant and would be nice to delegate to the DI framework.

Is this a breaking change?

It is difficult to imagine a scenario where this would cause a breaking change here; but of course, there is also the curse of hindsight

  1. Currently attaching a group attribute to a dependency type of map fails and the application would not start, therefore this cannot be a breaking change in a practical sense.
bad argument 1: bad field "Foo" of handler.Params: value groups may be consumed as slices only: field "Foo" (map[string]string) is not a slice
  1. Annotating a provided dependency with both a name and a group similarly fails:
bad result 1: bad field "Foo" of handler.Result: cannot use named values with value groups: name:"foo1" provided with group:"myfoos"

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions