-
Notifications
You must be signed in to change notification settings - Fork 208
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
Allow to specify an interface when providing a constructor #197
Comments
Hello! This is a good question and a recurring problem. Although it's possible for dig to map structs to interfaces, we explicitly That said, this is still something we would like to simplify in the future. A We'll keep an eye out for a design that solves this well, but until then the A ProvideOption that allows you to specify the concrete implementation would
You'd have to provide the type information through another concrete type that
IMO that's more confusing than just,
|
Hi @abhinav They are both valid points so i'll just keep doing something along the lines of providing Thanks for the clarification and open sourcing this library I'll close the issue |
Re-opening because another possible API came up. We can pass references to
We'll want to figure out naming to make it explicit that this isn't an |
To me Or you could use |
If this solution is implemented in combination with the one suggested in #181 It will make the following code shorter
by using
|
Until then, we suggest continuing to use the explicit |
Going back to one of the original comments:
Yes, it's true that in Go interfaces are implicit. However, in the case of a dependency injection container it's a good thing that you have to declare who implements what since there can never be an ambiguity. Consider the following example: type A struct {}
func (a A) String() { } // implements fmt.Stringer
type B struct {}
func (b B) String() { } // implements fmt.Stringer
// fx.Provide(NewA, NewB)...
func New(s fmt.Stringer) {} // constructor requiring a fmt.Stringer In the scenario above, there is an ambiguity. Both objects implement a stringer (it's easy for the container to check that). However, which object is to be returned in that case? An error would have to be thrown in this case about too may stringers in the container, which is not desired since those two objects should be able to coexist just fine. |
@glibsm yeah, @abhinav already clarified that point in his response #197 (comment) I'll update the title of the issue. |
@abhinav updates on this? |
@abhinav Perhaps also |
The For Fx, now that we have
|
Ah, that's right. The |
Would it be possible to either:
|
That is not an option for two reasons:
There is a very good post by Dave Cheney on this topic: https://dave.cheney.net/2014/10/17/functional-options-for-friendly-apis Essentially, we don't want to redefine a new method any time some option is introduce (like casting to another interface). We intentionally left room in the API signature of Provide to allow us to introduce new options and features without API breaking changes. |
The first option wouldn't be a breaking change because it allows zero or more parameters to be passed into the function. Not one or more. So you also wouldn't be required to pass it into the function. https://golang.org/ref/spec#Passing_arguments_to_..._parameters |
I'm not sure I follow.
Please illustrate through a code sample what you are suggesting and it's affect on the API. |
Ah, I didn't see that there was already a Would it be possible to then add to the |
Yep. See the discussion earlier in this issue #197 (comment) |
This adds a dig.As option which allows the caller to specify a constructor and a list of interfaces that the constructed struct implements. Closes uber-go#197
This adds a dig.As option which allows the caller to specify a constructor and a list of interfaces that the constructed struct implements. Closes uber-go#197
This adds a dig.As option which allows the caller to specify a constructor and a list of interfaces that the constructed struct implements. Closes uber-go#197
This adds a dig.As option which allows the caller to specify a constructor and a list of interfaces that the constructed struct implements. Closes uber-go#197
This adds a dig.As option which allows the caller to specify a constructor and a list of interfaces that the constructed struct implements. Closes uber-go#197
This adds a dig.As option which allows the caller to specify a constructor and a list of interfaces that the constructed struct implements. Closes uber-go#197
This adds a dig.As option which allows the caller to specify a constructor and a list of interfaces that the constructed struct implements. Closes uber-go#197
This adds a dig.As option which allows the caller to specify a constructor and a list of interfaces that the constructed struct implements. Closes #197
This brings back #233. Per #235 (review), the issues we need to resolve are, 1. `dig.As` seems to indicate that it's a total override of the provided type. The way it currently works is it appends other interfaces on top of whatever the constructor already returns 2. semantics of `dig.Provide(func New() (Foo, io.Reader, error), dig.As(new(io.Writer)`. It currently fails due to inability to case reader to writer, but we'd want some extra validation here. Perhaps `dig.As` is only supported for a single type, error tuple? Closes #197
This brings back #233. Per #235 (review), the issues we need to resolve are, 1. `dig.As` seems to indicate that it's a total override of the provided type. The way it currently works is it appends other interfaces on top of whatever the constructor already returns 2. semantics of `dig.Provide(func New() (Foo, io.Reader, error), dig.As(new(io.Writer)`. It currently fails due to inability to case reader to writer, but we'd want some extra validation here. Perhaps `dig.As` is only supported for a single type, error tuple? Closes #197
Hi all, |
Manually constructing an object with a lambda. |
Hi all, any update? |
Same problem, and here is my solution. Different from google/wire, dig can't bind interface with specific value type. But dig can deal with interface and interface // receives value and returns interface
func BindFooer(f *Foo) Fooer {
return f
}
di.Provide(NewFoo)
di.Provide(BindFooer)
di.Invoke(func(f Fooer) {
fmt.Printf("f: %+v", f)
}) Of course, I know, writing the bind function every time is too much trouble, so can we bind interface with specific value type simply just like google/wire ? For example: // code from google/wire
wire.Bind(new(Fooer), new(*Foo))
wire.Bind(new(Barer), new(*Bar))
wire.Bind(new(Bazer), new(*Baz)) The answer is YES, here is the source code of // bind Fooer with Foo*
di.Provide(bind(new(Fooer), new(Foo)))
// bind Fooer with Foo
di.Provide(bind(new(Fooer), Foo{}))
// if you created Fooer already
var fooer Fooer
di.Provide(bind(&fooer, Foo{}))
func bind(interfaceValue interface{}, structValue interface{}) interface{} {
interfaceType := reflect.TypeOf(interfaceValue)
if interfaceType.Kind() == reflect.Ptr {
interfaceType = interfaceType.Elem()
}
if interfaceType.Kind() != reflect.Interface {
panic("the type of parameter 'interfaceValue' should be interface")
}
in := []reflect.Type{reflect.TypeOf(structValue)}
out := []reflect.Type{interfaceType}
funcType := reflect.FuncOf(in, out, false)
return reflect.MakeFunc(funcType, func(args []reflect.Value) (results []reflect.Value) {
return args
}).Interface()
} It works fine for me, good luck |
Binding also works for me. Thank you. |
This brings back uber-go#233. Per uber-go#235 (review), the issues we need to resolve are, 1. `dig.As` seems to indicate that it's a total override of the provided type. The way it currently works is it appends other interfaces on top of whatever the constructor already returns 2. semantics of `dig.Provide(func New() (Foo, io.Reader, error), dig.As(new(io.Writer)`. It currently fails due to inability to case reader to writer, but we'd want some extra validation here. Perhaps `dig.As` is only supported for a single type, error tuple? Closes uber-go#197
#293 added |
Update (by @glibsm)
The addition of
dig.As
ProvideOption
has been agreed on.Currently
dig
only uses a constructors that returns exactly what the function expects.If the function accepts an interface, and we don't inject the constructor that returns that interface we get this error
Take the following example
So to make it work it needs to have a constructor function such as:
which is basically making us declare thatFoo implements Fooer
Would it be feasible to change the library so that it can workout itself if the struct implements the interface?[edit] as clarified in the comments this suggestion won't workOr alternatively, add a new
ProvideOption
which allow us to specify which concrete implementation to inject for a given interface?The text was updated successfully, but these errors were encountered: