I've removed the issue template, because this is a proposal and not an issue. Sorry if this is the wrong place, or even a duplicate, I've searched the repo for issues, but the terms give too much hits. None of them seemed related.
Often it is a good practice to encode something that could be parameters to a function in a struct type. For once it reduces the number of arguments to the function, makes it easy to extend the struct with new fields without breaking existing consumers, and also allows for "default" values in a way.
Repeatedly, I've had the situation that I already have a struct with the required fields, but the function I want to call takes another struct type. Even though that other type has the exact same fields (which often are a subset of the fields of the struct I already have), I have to convert the two structs.
My proposal is to extend the meaning of interfaces to optionally include public fields.
Then a function signature can be rewritten to take an interface type, with the requirements that the struct has certain public fields (name and type). This would eliminate the requirement to convert types so often, when all this does is copy the values of fields that have the same name and type in two different struct types.
Please note that you should fill https://github.com/golang/proposal/blob/master/go2-language-changes.md when proposing a language change.
If the two structs have _exactly_ the same fields, you can actually just convert from one to the other. Although, if you know that they're going to have the same fields, it probably makes more sense to define one from the other, such as type B A.
For structs that are subsets of another, perhaps you could simplify it via embedding. For example, if you have
type A struct {
X string
Y int
}
type B struct {
X string
}
consider using
type A struct {
B
Y int
}
type B struct {
X string
}
instead. Now if you want to create the larger struct from the subset, you can just do a := A{B: b}, which would allow for a.X just fine, or a.B for the other direction.
I don't think that it makes sense to put fields in interfaces, as it then ties interfaces, which are supposed to be a pure functionality abstraction, directly to memory layout, and also restricts any interfaces that have them to only having structs. If you need to pass multiple, completely different types to a function, it probably makes more sense to attach methods to those types that access the pieces of data required, or converts the type to an entirely new, standardized type, such as how color.Color works, and then make the function argument an interface that has that method set. If you tie this too much to multiple structs with completely separate definitions that just _happen_ to have the same fields, it's going to make your code quite a bit more breakable.
The differentiating feature about interfaces in Go is that they allow loose coupling. This is the aspect I am focussing on.
In the use-cases that motivated this proposal, the structs that I want to directly pass into some function are generated. There is only control over the names and types of fields. But that's besides the point. I want something elegant and the above solutions (that I am aware of), are not really elegant.
With an interface, I declare my expectations. "I expect a struct type that has these methods."
Why is it not elegant to extend that also to public fields? "I expect a struct that has these fields."
Public fields can by definition be r/w accessed directly. The pure reason they exist is that you can access them without going through a function, and there are plenty use-cases for having them. They replace pure setters/getters without any additional functionality, which some other languages have auto-generated.
Also, when a function signature takes an interface type, it always takes it by pointer. So there shouldn't be an issue with the fact that the actual size of the struct is not known at compile time. There is the complication that the memory offset of the fields is not known, so there probably is a performance hit. But the order of methods is also not defined in an interface, so it is probably a similar indirection as with functions. In any case, I don't consider this a reason for rejecting this proposal. It should be considered purely on what benefit it gives and how well it fits into the Go philosophy. I don't mean I know what that is, but rather that the discussion should be around those aspects. Not that it should be rejected, because there is some cumbersome alternative. The whole point is to find a better solution versus what is currently possible.
it then ties interfaces, which are supposed to be a pure functionality abstraction, directly to memory layout
1) Why?
2) Interfaces are an abstraction, but their location is flipped compared to other languages. As such, interfaces are a declaration of expectations. I don't see the necessity to restrict the type of expectations that they can express.
and also restricts any interfaces that have them to only having structs
I don't understand what you mean by that.
If I understand this correctly, I think it's a duplicate of #23796.
and also restricts any interfaces that have them to only having structs
I don't understand what you mean by that.
Right now any kind of type can satisfy any interface, if it just defines the right methods. With this proposal, if an interface has fields, then only a struct type will be able to satisfy such an interface.
A little off-topic, if field contracts are needed, is it good to use interface to define them?
Interfaces have been depicted as a method set in many docs, including official ones.
In fact, it is already some weird to me by using iterfaces to define type list.
If I understand this correctly, I think it's a duplicate of #23796.
Yes, it absolutely is.
and also restricts any interfaces that have them to only having structs
I don't understand what you mean by that.Right now any kind of type can satisfy any interface, if it just defines the right methods. With this proposal, if an interface has fields, then only a struct type will be able to satisfy such an interface.
Ah, thanks for the explanation. But I don't really understand, why that restriction cannot apply only to those interfaces that declare fields. Interfaces that contain methods only, could work as before. While I do see the argument, languages often balance strict logic and convenience. And this extension would help a lot in avoiding to write code that feels cumbersome right now.
In any case, I've read through the other discussion, it contains a lot of additional arguments. No reason to keep this open.