-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
proposal: Go 2: allow packages to implement interfaces using .(package) syntax #28506
Comments
It's an interesting idea, but I'm not sure what the point is. Why not just export a global instance of a type, possibly satisfying an interface, such as |
Sure, in the simpler cases ( What this proposal is meant to be is to improve generality
Commenting on that: But why directly export a specific implementation? Let take the example from Effective Go that would follow the quote above.
Any Algorithm that satisfies Block can be used in
With the proposal implemented, all algorithms could provide ready-to-use, default instances with sane default values, where accessing the default instance is the same in all cases: var block Block
switch alg {
case "aes":
block = aes.(package)
case "des":
block = des.(package)
} var algorithm cipher.Block
candidates := []interface{}{rsa.(package), aes.(package), des.(package)}
for _, cand := range candidates {
if alg, ok := cand.(cipher.Block); ok {
algorithm = alg
break
}
} |
Consider the following statement in the current generics proposal:
What you have essentially done is turn package-level functions into methods on the package; the (current) generics draft would be unable to work, assuming that So I have a few questions:
|
ClarificationEvery package defines an interface by default and automatically, which contains the signatures of all exported package-level functions. To your questions:
Yes, following the logic above,
Because an interface is returned,
Here I'm unsure, quiet honestly. It could be simply evaluated to
Optimally, you would only discover exported functions/values. That includes
Again,
Generally speaking, this change might encourage package maintainers to follow the Generality Directive more closely. Thank you @deanveloper for your questions, they made me think about the scope more thoroughly :simple_smile: Regarding the generics proposal (omg what?) - I believe you mean this one: Sorry, but I am unfamiliar with it. If I find the time, I will take a look at it. |
I didn't quite understand that
Because functions can be seen as values as well, my bad as I didn't understand that it was an interface that was returned again.
Well if its an interface, again I have some more questions... also my question becomes irrelevant 😅
I mean the practice of providing a What I was wondering with my original question was if this feature would add another reason not to provide the equivalent of a I feel like this is a very unlikely situation that I'm questioning the validity of as I'm writing it, but I'm leaving it included anyway, haha
My previous comment was more trying to say the opposite, that it may encourage people not to do things like making a private, global Also, the (better) link for the Go2 draft is here, which contains a link to the documents relating to the generics draft (please remember that these are only drafts, and are not final in any way, and are not official proposals) Anyway, onto my new questions
With these questions, what I'm getting at is that interfaces are a bit more than just a "set of methods", they have real types and values underneath them. Perhaps we could have a I know I'm criticizing this pretty hard, I don't mean for it to be in any way. I'm usually pretty critical of "synthetics" (types/values that are just magically created for specific purposes). I personally think that instead, you should just create your own interface, match your package to the interface, and provide a package-level variable if you want to pass it around as a value, but that's just my opinion |
I'm concerned that this proposal would mean that the linker could not remove any exported functions from the generated binary, because it would not be able to be certain that the function was not referenced via an interface obtained via |
That's already true for interface methods in general (see #25081), and unused interface methods can also pull in arbitrarily large graphs of package-level functions. It's certainly possible that |
Another option might be to construct a minimal interface rather than a maximal one, including only the functions needed to satisfy the interface rather than all functions. (Failing to make some functions available via type-assertion seems better than pinning all of the code reachable from package-level functions.) For example, we could use the type Registerer interface {
Register(interface{}) error
}
func main() {
var srv Registerer
if (os.Getenv("default") != "") {
srv = make(Registerer, rpc)
} else {
srv = rpc.NewServer()
}
} var block Block
switch alg {
case "aes":
block = make(Block, aes)
case "des":
block = make(Block, des)
} If we wanted to extend that pattern further, we could employ the same syntax to convert functions to interfaces (#21670) or to promote the fields of type io interface {
Read(p []byte) (n int, err error)
ReadAt(p []byte, off int64) (n int, err error)
WriteTo(w io.Writer) (n int64, err error)
}
func ReaderWithContext(ctx context.Context, r Reader) io.Reader {
[…]
wrap := make(io, {
Read: ctxr.Read,
ReadAt: nil,
WriteTo: writeToFn,
})
return wrap
} |
We could change the plugin mechanism to make use of such package interfaces, i.e. That would make the contract between the main binary and the plugins more clear and visible and |
seem you all just need dynamic lib like DLL, SO, not platform limit. most like |
The mechanism to create objects that satisfy an interface is defining new types with methods. Packages have a different function: they provide encapsulation and modularity. There is no mechanism to create multiple instances of a single package. In Go, packages are not values. We shouldn't start treating them as though they are. |
Proposal
Given the following interface and function:
A package itself would implement / satisfy the interface
Foo
if it exported aBar(string) (string, error)
function:I propose a backwards compatible syntax extension similar to the
.(type)
syntax:I believe that this extension works well with the composition paradigm as a package is a composition of files. Optimally, the exported functions are pure of some form, so that the behavior of a given package-level implementation can easily be determined.
Example
Access to functions of a default instance without having actually access to that instance:
I find the proposed change intuitive and suitable for my needs. I hope it aligns with the direction golang is taking and that more people find it suiting their needs 😅. Thank you for your time.
I love golang and thank all previous contributors for their amazing work.
The text was updated successfully, but these errors were encountered: