Skip to content
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: Allow interfaces to define fields #43246

Closed
stippi2 opened this issue Dec 17, 2020 · 7 comments
Closed

proposal: Allow interfaces to define fields #43246

stippi2 opened this issue Dec 17, 2020 · 7 comments
Labels
FrozenDueToAge LanguageChange Proposal v2 A language change or incompatible library change WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Milestone

Comments

@stippi2
Copy link

stippi2 commented Dec 17, 2020

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.

@gopherbot gopherbot added this to the Proposal milestone Dec 17, 2020
@mvdan
Copy link
Member

mvdan commented Dec 17, 2020

Please note that you should fill https://github.com/golang/proposal/blob/master/go2-language-changes.md when proposing a language change.

@mvdan mvdan added the WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided. label Dec 17, 2020
@DeedleFake
Copy link

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.

@stippi
Copy link

stippi commented Dec 17, 2020

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.

@stippi
Copy link

stippi commented Dec 17, 2020

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.

@ianlancetaylor
Copy link
Contributor

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.

@ianlancetaylor ianlancetaylor added v2 A language change or incompatible library change LanguageChange labels Dec 17, 2020
@go101
Copy link

go101 commented Dec 18, 2020

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.

@stippi
Copy link

stippi commented Dec 18, 2020

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.

@golang golang locked and limited conversation to collaborators Dec 18, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
FrozenDueToAge LanguageChange Proposal v2 A language change or incompatible library change WaitingForInfo Issue is not actionable because of missing required information, which needs to be provided.
Projects
None yet
Development

No branches or pull requests

8 participants