-
Notifications
You must be signed in to change notification settings - Fork 221
Refactor dig to separate graph handling and calling API #29
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
Conversation
HelloGrayson
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see where you're going with this, but can you help me understand why we think we need locking?
| // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
| // THE SOFTWARE. | ||
|
|
||
| package graph |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's move this package internal/ - I'd like to keep the API surface as small as possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 agreed. moving to internal.
| ) | ||
|
|
||
| // Graph contains all Graph for current graph | ||
| type Graph struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Im still thinking through this PR, but one thing is for certain: we don't want this to be a public type that users can interact with. It should either be private in the same package, or at the very least an internal package.
We have known for a while that options are coming: things like named instances, or private non-shared instances. I'd like for us to start thinking and working through those APIs, because only then we will be able to tell if this refactor is a good or bad thing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving to internal package to avoid exposing graph to public.
With options coming, this will save us lot of headache of dealing with locks, maps, and reflect :)
|
@breerly Locking is needed right now because we have APIs reading and iterating over the |
container.go
Outdated
| switch v.Type().Kind() { | ||
| case reflect.Ptr: | ||
| c.insertObjectToGraph(v, v.Type()) | ||
| c.Graph.InsertObject(v, v.Type()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
looks like we should strip type from the InsertObject, container should get it form the object itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good point. I'll update.
| type Graph struct { | ||
| sync.RWMutex | ||
|
|
||
| nodes map[interface{}]graphNode |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why it is a map[interface{}]graphNode not a map[reflect.Type]graphNode?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't want to change the map type in the same PR as it will get hard to read and change. Will follow up.
| } | ||
| for i := 0; i < argc; i++ { | ||
| arg := ctype.In(i) | ||
| if arg.Kind() != reflect.Ptr && arg.Kind() != reflect.Interface { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm, should the container care about it? Extending for slices and map will be hard then.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are constructing values from the node, which container isn't aware of, so as of this PR graph is ideal place for building constructor arguments. I'll add/change it once slices and maps are introduced.
|
Changes Unknown when pulling 53fa0da on refactor into ** on master**. |
| n, ok := g.nodes[objType] | ||
| g.RUnlock() | ||
| if !ok { | ||
| return reflect.Zero(objType), fmt.Errorf("type %v is not registered", objType) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: just reflect.Value{}?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the other hand, why return values, not pointers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We set the pointer value of the provided object to the instance pointer in container. It makes sense since the function is defined to read value from the graph.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also,"reflect.Zero returns a Value representing the zero value for the specified type." seems more appropriate to return as a default than reflect.Value{}?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is no point of having a reflect.Value of specific type if there is an error :)
My comment was about unnecessary copying of reflect.Value that is going all around the graph. After digging through the code it looks like you'll need to change the graphNode interface to avoid it. May be another time then.
internal/graph/graph.go
Outdated
| } | ||
|
|
||
| // InsertConstructor adds the constructor to the Graph | ||
| func (g *Graph) InsertConstructor(constr interface{}) error { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: usually constructor is abbreviated with ctor, constr is to close to const :)
internal/graph/graph.go
Outdated
|
|
||
| // When a new constructor is being inserted, detect any present cycles | ||
| func (g *Graph) detectCycles(n *funcNode) error { | ||
| l := []string{} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's not needed, recursiveDetectCycles will work with nil too.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
interesting..
|
Changes Unknown when pulling b218032 on refactor into ** on master**. |
access to the nodes map, duplicate code, and all the locking logic is getting difficult to work around. This refactor should help.
package dig(Provide,Resolve,Invoke, etc)pros - container doesn't know about nodes map.
package graphcontains all the logic to insert object/constructors to the graph, read values from the graph and maintain locking throughout the usage.pros- graph can manage its own lock