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

Decorators at parent level scope affects child only after an invoke at parent scope #316

Closed
sywhang opened this issue Feb 4, 2022 · 0 comments · Fixed by #317
Closed
Assignees
Labels

Comments

@sywhang
Copy link
Contributor

sywhang commented Feb 4, 2022

Suppose:

type A struct {
  Name string
}


c := dig.New()
child := c.Scope("child")

c.Provide(func() *A { return &A{Name: "A") })
c.Decorate(func(a *A) *A { return &A{Name: a.Name + "'" }})

Then:

c.Invoke(func(a *A) { fmt.Println(a.Name) })
child.Invoke(func(a *A) { fmt.Println(a.Name) })

prints two lines of A'.

But if we do this instead:

child.Invoke(func(a *A) { fmt.Println(a.Name) })

It prints A instead of A'.

@sywhang sywhang self-assigned this Feb 4, 2022
@sywhang sywhang added the bug label Feb 4, 2022
sywhang added a commit to sywhang/dig that referenced this issue Feb 6, 2022
When building paramSingle using decorators, there was a descrepancy when
the invoking Scope does not have a decorator for the type but one of its
parent Scopes does. This resulted in the parent Scope having to Invoke
a function that uses the decorated type for the child to start seeing it
too.

This fixes paramSingle to search all effective scopes for a decorator
and invoke that instead of searching just the scope it was invoked from.

Fixes uber-go#316
sywhang added a commit that referenced this issue Feb 8, 2022
When building paramSingle using decorators, there was a descrepancy when
the invoking Scope does not have a decorator for the type but one of its
parent Scopes does. This resulted in the parent Scope having to Invoke
a function that uses the decorated type for the child to start seeing it
too.

This fixes paramSingle to search all effective scopes for a decorator
and invoke that instead of searching just the scope it was invoked from.

Fixes #316
sywhang added a commit to uber-go/fx that referenced this issue Feb 10, 2022
This adds `fx.Decorate`, which lets you specify decorators to an fx app. A decorator can take in one or more dependencies that have already been `Provide`d to the app, and produce one or more values that will be used as replacements in the object graph.

For example, suppose there is a simple app like this:
```go
fx.New(
  fx.Provide(func() *Logger {
    return &Logger{Name: "logger"}
  }),
  fx.Invoke(func(l *Logger) {
    fmt.Println(l.Name)
  }),
)
```

Running this app will print "logger" on the console.

Now let us suppose a decorator was provided:
```go
fx.New(
  fx.Provide(...), // Provide same function as above
  fx.Decorate(func(l *Logger) *Logger {
    return &Logger{Name: "decorated " + l.Name}
  }),
  fx.Invoke(...), // Invoke same function as above
)
```

The decorator here will take in the provided Logger and replace it with another logger whose `Name` is `decorated logger`. The `Invoke`d function is then executed with this replacement value, so running this app will print "decorated logger" on the console.

In terms of implementation, a decorator is represented by the target decorator function and the call stack it was provided from, similar to a provider. `module` contains a list of decorators that were specified within its scope.

The dig dependency had to be updated to the latest master branch of Dig to ensure the fix for uber-go/dig#316 is in.

Following this PR, there are two additional pieces I will be adding:
1. An eventing system for fx.Decorate. 
2. fx.Replace, which takes in a value instead of a function to replace a value in the object graph. This is similar to what fx.Supply is to fx.Provide.

This PR along with the two PRs above should make the long-awaited feature of graph modifications in fx finally possible.

---

Refs #653, #649, #825, uber-go/dig#230, GO-1203, GO-736
luoboton added a commit to luoboton/fx that referenced this issue Aug 24, 2022
This adds `fx.Decorate`, which lets you specify decorators to an fx app. A decorator can take in one or more dependencies that have already been `Provide`d to the app, and produce one or more values that will be used as replacements in the object graph.

For example, suppose there is a simple app like this:
```go
fx.New(
  fx.Provide(func() *Logger {
    return &Logger{Name: "logger"}
  }),
  fx.Invoke(func(l *Logger) {
    fmt.Println(l.Name)
  }),
)
```

Running this app will print "logger" on the console.

Now let us suppose a decorator was provided:
```go
fx.New(
  fx.Provide(...), // Provide same function as above
  fx.Decorate(func(l *Logger) *Logger {
    return &Logger{Name: "decorated " + l.Name}
  }),
  fx.Invoke(...), // Invoke same function as above
)
```

The decorator here will take in the provided Logger and replace it with another logger whose `Name` is `decorated logger`. The `Invoke`d function is then executed with this replacement value, so running this app will print "decorated logger" on the console.

In terms of implementation, a decorator is represented by the target decorator function and the call stack it was provided from, similar to a provider. `module` contains a list of decorators that were specified within its scope.

The dig dependency had to be updated to the latest master branch of Dig to ensure the fix for uber-go/dig#316 is in.

Following this PR, there are two additional pieces I will be adding:
1. An eventing system for fx.Decorate. 
2. fx.Replace, which takes in a value instead of a function to replace a value in the object graph. This is similar to what fx.Supply is to fx.Provide.

This PR along with the two PRs above should make the long-awaited feature of graph modifications in fx finally possible.

---

Refs #653, #649, #825, uber-go/dig#230, GO-1203, GO-736
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

Successfully merging a pull request may close this issue.

1 participant