Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Update dependencies to support Generics #360

Merged
merged 2 commits into from
Jun 20, 2022
Merged

Conversation

efueyo
Copy link
Contributor

@efueyo efueyo commented May 19, 2022

Hello! First of all, thanks for this project. It is very helpful and makes dependency injection a breeze.

We've experience some problems working with wire and generics (as I think other people has experienced too according to #354)

I dont know for sure if these changes added full support for generics but I've managed to fix all the issues I had in my projects.

Mainly, I had to update the dependencies to use golang.org/x/tools@v0.1.10

The main issue was here:
https://github.com/golang/tools/blob/master/go/ast/astutil/rewrite.go#L255
that was included in this commit

this is a version adapted from the tutorial that works only with the updated version:

// main.go
package main

import (
	"errors"
	"fmt"
	"os"
	"time"
)

// Message is what greeters will use to greet guests.
type Message string

type Resolver[K comparable, V any] struct {
	store map[K]V
}

func NewResolver[K comparable, V any]() Resolver[K, V] {
	return Resolver[K, V]{
		store: map[K]V{},
	}
}

func (o Resolver[K, V]) Resolve(key K) (V, error) {
	val, exists := o.store[key]
	if !exists {
		return val, errors.New("not found")
	}

	return val, nil
}

func (o Resolver[K, V]) Add(key K, val V) {
	o.store[key] = val
}

// NewMessage creates a default Message.
func NewMessage(phrase string) Message {
	return Message(phrase)
}

// NewGreeter initializes a Greeter. If the current epoch time is an even
// number, NewGreeter will create a grumpy Greeter.
func NewGreeter(m Resolver[bool, Message]) Greeter {
	var grumpy bool
	if time.Now().Unix()%2 == 0 {
		grumpy = true
	}
	return Greeter{MessageResolver: m, Grumpy: grumpy}
}

// Greeter is the type charged with greeting guests.
type Greeter struct {
	Grumpy          bool
	MessageResolver Resolver[bool, Message]
}

// Greet produces a greeting for guests.
func (g Greeter) Greet() Message {
	m, err := g.MessageResolver.Resolve(g.Grumpy)
	if err != nil {
		return Message("not found")
	}
	return m
}

// NewEvent creates an event with the specified greeter.
func NewEvent(g Greeter) (Event, error) {
	if g.Grumpy {
		return Event{}, errors.New("could not create event: event greeter is grumpy")
	}
	return Event{Greeter: g}, nil
}

// Event is a gathering with greeters.
type Event struct {
	Greeter Greeter
}

// Start ensures the event starts with greeting all guests.
func (e Event) Start() {
	msg := e.Greeter.Greet()
	fmt.Println(msg)
}

func main() {
	e, err := InitializeEvent("hi there!")
	if err != nil {
		fmt.Printf("failed to create event: %s\n", err)
		os.Exit(2)
	}
	e.Start()
}
// wire.go
package main

import "github.com/google/wire"

func getMessageResolver() Resolver[bool, Message] {
	r := NewResolver[bool, Message]()
	r.Add(false, Message("happy false"))
	r.Add(true, Message("grumpy true"))
	return r
}

// InitializeEvent creates an Event. It will error if the Event is staffed with
// a grumpy greeter.
func InitializeEvent(phrase string) (Event, error) {
	wire.Build(NewEvent, NewGreeter, getMessageResolver)
	return Event{}, nil
}

@google-cla
Copy link

google-cla bot commented May 19, 2022

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

For more information, open the CLA check for this pull request.

@efueyo
Copy link
Contributor Author

efueyo commented May 20, 2022

Thanks for your pull request! It looks like this may be your first contribution to a Google open source project. Before we can look at your pull request, you'll need to sign a Contributor License Agreement (CLA).

For more information, open the CLA check for this pull request.

signed ⚡ ✍️

Copy link
Collaborator

@jayzhuang jayzhuang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Enrique!

Currently it requires getMessageResolver in wire.go to make wire happy. Ideally someone would want to say wire.Build(NewEvent, NewGreeter, getMessageResolver[bool, Message]) and expect things to just work. But this change is definitely a solid step forward, so LGTM!

@efueyo
Copy link
Contributor Author

efueyo commented May 26, 2022

Great @jayzhuang . should we merge this PR or wait until the whole functionality is there? (I'm now working with my forked repo and would love to come back to using the original go install github.com/google/wire instead of git clone + go install .)

@jayzhuang
Copy link
Collaborator

Hey Enrique, I'm supportive of merging this PR, but I don't have write access. @stytchiz can you take a look?

@giautm
Copy link
Contributor

giautm commented May 27, 2022

One vote for this PR, 👍 .

@efueyo
Copy link
Contributor Author

efueyo commented May 27, 2022

Hey Enrique, I'm supportive of merging this PR, but I don't have write access. @stytchiz can you take a look?

Understood, thanks for the support @jayzhuang

@stytchiz
Copy link
Collaborator

From the description ...

I dont know for sure if these changes added full support for generics but I've managed to fix all the issues I had in my projects.

Can you provide more details on what use case this PR is solving (as well as not solving)? I can take a deeper look during the weekend. My major concern is that this PR will down the line require supporting generics as a new feature which we don't have the bandwidth for at the moment.

@efueyo
Copy link
Contributor Author

efueyo commented May 30, 2022

Thanks for your comment @stytchiz. I understand the concern about bandwidth and it totally makes sense.

Regarding

I dont know for sure if these changes added full support for generics but I've managed to fix all the issues I had in my projects.

This was mostly a disclaimer or cautionary comment, since I didnt try all possible options involving generics.

In the first comment I provided an example where (google:main) wire . was failing but succeeded to wire the code with the changes from this PR.

To my understanding, this change doesnt include complete support for generics (like @jayzhuang commented): you cannot do wire.Build(NewEvent, NewGreeter, getMessageResolver[bool, Message]), it basically includes the changes needed to parse and understand ast.IndexList which is what is used in generics. So wire can tolerate code that includes generics, this gives us a way to work with generics without further changing wire.

The code from #354 still doesnt work with this change, however they would have a workaround. They just have to remove the generics from wire.Build and move it to an internal function:

Example from #354 that works changing their wire.go to this:

//go:build wireinject

package main

import "github.com/google/wire"

func getV() int {
	return NewV[int]()
}

func InitializeEvent() Event {
	wire.Build(NewEvent, NewGreeter, NewMessage, getV)
	return Event{}
}
Previous wire.go
//go:build wireinject

package main

// The build tag makes sure the stub is not built in the final build.

import "github.com/google/wire"

func InitializeEvent() Event {
	wire.Build(NewEvent, NewGreeter, NewMessage, NewV)
	return Event{}
}

Let me know if you need anything else and thanks for your support

@efueyo
Copy link
Contributor Author

efueyo commented Jun 13, 2022

Hello @stytchiz, I understand that you are very busy but I wanted to check if you had a chance to review the comment or if you need further information.
Best,
Enrique

@stytchiz
Copy link
Collaborator

Sorry for the delay @efueyo ! Your response was very helpful.

LGTM. The changes adds a new switch case for ast.IndexListExpr which should be invoked only for generics per https://go.googlesource.com/proposal/+/master/design/47781-parameterized-go-ast.md#for-type-and-function-instantiation.

I'll also update #354 that this is a workaround and that full support for generics is not on the table.

@stytchiz stytchiz merged commit 4aee85e into google:main Jun 20, 2022
@efueyo
Copy link
Contributor Author

efueyo commented Jun 20, 2022

Thanks for your support and c

Sorry for the delay @efueyo ! Your response was very helpful.

LGTM. The changes adds a new switch case for ast.IndexListExpr which should be invoked only for generics per https://go.googlesource.com/proposal/+/master/design/47781-parameterized-go-ast.md#for-type-and-function-instantiation.

I'll also update #354 that this is a workaround and that full support for generics is not on the table.

No need to apologize, I understand we all might be very busy. Thanks for finding the time to carefully look at this, though!

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants