uber-go / dig

A reflection based dependency injection toolkit for Go.
https://go.uber.org/dig
MIT License
3.78k stars 206 forks source link

Root container provided function may look provided parameter in child scope too to resolve it's params #374

Open alexisvisco opened 1 year ago

alexisvisco commented 1 year ago

Describe the bug When a invoker need a parameter that is provided by the root container, and the provided function need a param that is provided by the child scope : the parameter needed for invoking the function will not be resolved

To Reproduce

package main

import (
    "fmt"
    "go.uber.org/dig"
)

type config struct {
    str               string
    boolPassedInScope bool
}

func main() {

    mainContainer := dig.New()

    mainContainer.Provide(func() string { return "Hello" })

    // boolPassedInScope will be passed in the child scope
    mainContainer.Provide(func(helloStr string, boolPassedInScope bool) config {
        return config{str: helloStr, boolPassedInScope: boolPassedInScope}
    })

    scope := mainContainer.Scope("newscope")

    scope.Provide(func() bool { return true })

    // this will fail because boolPassedInScope is not provided in the main scope
    // and the config cannot be resolved due to the fact that in the mainContainer there
    // is no boolean provided
    err := scope.Invoke(func(c config) {
        fmt.Println(c.str)
        fmt.Println(c.boolPassedInScope)
    })

    if err != nil {
        panic(err)
    }

}

Expected behavior I don't know if it's possible but without adding dig.Export to the line scope.Provide(func() bool { return true }) the provided function to create the config should look in the child scope to find the boolPassedInScope.

Additional context Maybe my approach is wrong but in my application framework I need to pass context, logger that is scoped because I launch multiple invoke in parallel so I can't just set them in the root container (because the logger and ctx is customized for the invoker).

Also I can't use named dig parameter because the invoker signature must not change.

r-hang commented 1 year ago

Hey @alexisvisco, the current design intends for child types to not be available in their parent scopes.

One possible option is to utilize a value group in the parent scope to contain all of the unique values that you were producing in your child scopes that you could call your scoped invokes with. Here the invoker signature would not change.