From 776f1c454133ddeb7b895d9a378705b77fc207a8 Mon Sep 17 00:00:00 2001 From: Matt Kocubinski Date: Thu, 9 Jun 2022 16:49:24 -0500 Subject: [PATCH 1/2] Update README for depinject --- depinject/README.md | 92 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 90 insertions(+), 2 deletions(-) diff --git a/depinject/README.md b/depinject/README.md index c234bead99de..5cb7b6d8b2f8 100644 --- a/depinject/README.md +++ b/depinject/README.md @@ -7,7 +7,8 @@ to simplify the definition of a blockchain by replacing most of app.go's boilerp ## Usage -### `depinject` example +`depinject` includes an expressive and composable [Configuration API](https://pkg.go.dev/github.com/cosmos/cosmos-sdk/depinject#Config). +A core configuration is `Provide`, for example this code snippet ```go package main @@ -15,7 +16,7 @@ package main import ( "fmt" - "cosmossdk.io/depinject" + "github.com/cosmos/cosmos-sdk/depinject" ) type AnotherInt int @@ -39,6 +40,93 @@ func main() { } ``` +demonstrates the registration of free **provider functions** via the `Provide` API. Provider functions form the basis of the +dependency tree, they are introspected then their inputs identified as dependencies and outputs as dependants, either for +another provider function or state stored outside the DI container, as is the case of `&x` and `&y` above. + +### Interface type resolution + +`depinject` supports interface types as inputs to provider functions. In the SDK's case this pattern is used to decouple +`Keeper` dependencies between modules. For example `x/bank` expects an [AccountKeeper](https://pkg.go.dev/github.com/cosmos/cosmos-sdk/x/bank/types#AccountKeeper) interface as [input to provideModule](https://github.com/cosmos/cosmos-sdk/blob/de343d458aa68c19630177807d6f0e2e6deaf7a9/x/bank/module.go#L224). +Concretely `SimApp` uses the implementation in `x/auth`, but this design allows for this loose coupling to change. + +Given the following types + +```golang +package duck + +type Duck interface { + quack() +} + +type AlsoDuck interface { + quack() +} + +type Mallard struct{} +type Canvasback struct{} + +func (duck Mallard) quack() {} +func (duck Canvasback) quack() {} + +type Pond struct { + Duck AlsoDuck +} +``` + +This usage + +```golang +var pond Pond + +depinject.Inject( + depinject.Provide( + func() Mallard { return Mallard{} }, + func(duck Duck) Pond { + return Pond{Duck: duck} + }), + &pond) +``` + +results in an *implicit* binding of `Duck` to `Mallard`. This works because there is only one implementation of `Duck` +in the container. However, adding a second provider of `Duck` will result in an error: + +```golang +var pond Pond + +depinject.Inject( + depinject.Provide( + func() Mallard { return Mallard{} }, + func() Canvasback { return Canvasback{} }, + func(duck Duck) Pond { + return Pond{Duck: duck} + }), + &pond) +``` + +A specific binding preference for `Duck` is required. + +#### `BindInterface` API + +In the above situation registering a binding for a given interface binding may look like + +```golang +depinject.Inject( + depinject.Configs( + depinject.BindInterface( + "duck.Duck", + "duck.Mallard"), + depinject.Provide( + func() Mallard { return Mallard{} }, + func() Canvasback { return Canvasback{} }, + func(duck Duck) APond { + return Pond{Duck: duck} + })), + &pond) +``` + +Now `depinject` has enough information to provide `Mallard` as an input to `APond`. + ### Full example in real app ```go From 7e6e038da4f6f08f22037c594213e4d1d2b6f282 Mon Sep 17 00:00:00 2001 From: Julien Robert Date: Tue, 19 Jul 2022 12:16:12 +0200 Subject: [PATCH 2/2] Update depinject/README.md --- depinject/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/depinject/README.md b/depinject/README.md index 5cb7b6d8b2f8..bfbb7276347f 100644 --- a/depinject/README.md +++ b/depinject/README.md @@ -16,7 +16,7 @@ package main import ( "fmt" - "github.com/cosmos/cosmos-sdk/depinject" + "cosmossdk.io/depinject" ) type AnotherInt int