-
Notifications
You must be signed in to change notification settings - Fork 110
Description
EDIT: The orginal issue was to return a concrete type from NewIndex. The issue is now about differing between an IndexBuilder and a compiled Index which serve different usage patterns and requirements. See comments for more details
Original idea
@rs, I am raising this as a potential enchantment only.
It appears to be an idiom in Go to return concrete types, and accept interfaces. resource.NewIndex()
is breaking this idiom. I see the following benefits for correcting it:
index.Compile()
would no longer be a "hidden" function, so user would not have to type-cast the returned index to a Compiler instance if using the returned Index without the rest handlers.- The documentation in editors (i.e. with go-to-definitions and auto-complete) would be able to display help-text when calling methods on the returned index.
These are not huge benefits, but if there is no obvious downside to the change, except for a limited change to the public API, it might be worth-while. There are also some consequences that could come out of how we fix this that we need to consider.
resource.Resource
implements the Index interface. Could/should Bind accept a version of the Index interface? (probably not)- Where the Index interface is used, du we require all of the functions, or generally just the Getter functions? Should the interface be split?
Background: General information on the idiom
Some blogs on the subject:
- http://idiomaticgo.com/post/best-practice/accept-interfaces-return-structs/
- https://medium.com/@cep21/what-accept-interfaces-return-structs-means-in-go-2fe879e25ee8
TL;DR with some added personal experience:
Generally, returning the concrete type makes sense because:
- When we write a function, we always know what type it will return (when we don't, such as for errors, returning an interface still make sense).
- When we return the concrete type, users can access all public functions on the returned type.
- Documentation in auto-complete and go-to-definition is generally better.
Likewise, it makes sense to accept interfaces because:
- We allow for a wider usage of the API, as users may provide their own implementations, or wrapped implementations.
- We achieve better documentation, since the function declaration itself can document which methods we are interested in using on the passed in type.
- We allow for mocking during testing.
Sometimes these points doesn't match with our goals, and then it's probably correct to break the idiom.