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

Invoke with provided args? #214

Closed
rubensayshi opened this issue Oct 3, 2018 · 1 comment
Closed

Invoke with provided args? #214

rubensayshi opened this issue Oct 3, 2018 · 1 comment

Comments

@rubensayshi
Copy link

rubensayshi commented Oct 3, 2018

Would it be an idea to let Invoke take arguments that aren't coming from the container?
it seems rather straight forward to add this ( I managed in like 15min by just fiddling in my vendor folder ), which leads me to belief it's not in there for a (good) reason...?

something like;

// my super complicated service
type MyService struct {
	Booyaa bool
}

// provide for my super complicated service
func NewMyService() *MyService {
	return &MyService{}
}

func CanWeBooyaa(ctx *gin.Context, service *MyService) {
	ctx.String(200, fmt.Sprintf("booyaa? %v! \n", service.Booyaa))
}

container := dig.New()
container.Provide(NewMyService)

ctx := &gin.Context{}
container.Invoke(CanWeBooyaa, ctx)
@abhinav
Copy link
Collaborator

abhinav commented Oct 3, 2018

Hello. This is an intriguing idea and I think it would be beneficial for
certain use cases, but it introduces a few problems.

First, we have to ask if the arguments are provided based on positions or
based on their types? For this to be valuable, they have to be position-based
because if they are type-based, you could just c.Provide them. The main
benefit of this would come from doing c.Invoke(f, "foo") because you can't
provide "foo" into the container (since string is super generic and surely
you have more than one of those sitting around).

So given that the arguments are positional, how do we support the case where I
want to have the first argument injected and I want to provide the second one?
What if I want all but the third argument injected by dig? This would probably
result in a sentinel-value based API like c.Invoke(f, "foo", dig.Inject, "bar").

Additionally, for that API to be backwards compatible, it would have to be an
Invoke option. c.Invoke(f, dig.PartialArgs("foo", dig.Inject, "bar")).

Is all that complexity worth it versus just writing the closure by hand?

Finally, arguably, this functionality doesn't need to reside in Dig at all.
Using reflection, you can implement a function with the following signature
that, given a function and some positional arguments, returns a new function
with those positional arguments applied to it.

func Partial(f interface{}, args ...interface{}) interface{}

This would work with both, Invoke and Provide.

c.Provide(Partial(f, "foo"))
c.Invoke(Partial(CanWeBooyaa, ctx))

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants