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

spec: methods of the embedded struct field won't be promoted in two cases #69557

Closed
TutiFrouti opened this issue Sep 20, 2024 · 6 comments
Closed
Labels

Comments

@TutiFrouti
Copy link

What is the URL of the page with the issue?

https://go.dev/ref/spec#Struct_types

What is your user agent?

Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/127.0.0.0 Safari/537.36

Screenshot

No response

What did you do?

Specification for the promoted methods of the embedded struct field states:

Given a struct type S and a named type T, promoted methods are included in the method set of the struct as follows:

  • If S contains an embedded field T, the method sets of S and *S both include promoted methods with receiver T. The method set of *S also includes promoted methods with receiver *T.
  • If S contains an embedded field *T, the method sets of S and *S both include promoted methods with receiver T or *T.

However, promoted methods won't be included in 2 cases:

  1. if the method with the same name (identifier) is already defined for the struct type in which we embed
  2. if two (or more) methods of the embedded fields that would be promoted have the same method name (identifier)

What did you see happen?

I created an example for each case. Note that only method names are the same, but the signatures are different.

First case:

type T struct{}

func (T) Method(int) string { return "" }

type S struct {
	T
}

func (S) Method() {}

type I interface {
	Method(int) string
}

func main() {
	var _ I = S{} // InvalidIfaceAssign error
}

Second case:

type T1 struct{}

func (T1) Method(int) string { return "" }

type T2 struct{}

func (T2) Method(float32) string { return "" }

type S struct {
	T1
	T2
}

type I interface {
	Method(int) string
}

func main() {
	var _ I = S{} // InvalidIfaceAssign error
}

What did you expect to see?

I expect to see these two constrains for the promoted methods included in the specification.

@TutiFrouti
Copy link
Author

TutiFrouti commented Sep 20, 2024

In my opinion it is not duplicate of the #14309. Specification states that the method names must be unique in the method set. I agree with that. Since the methods won't even be promoted in either my or the #14309 example, these programs are valid and should compile (if I omit assigning).

I am talking here about adding note about cases when methods won't even be promoted and thus won't be part of the method set.

@adonovan
Copy link
Member

See the spec wording on Selectors and the concept of depth. I think the first rule below addresses both of your concerns:

A selector f may denote a field or method f of a type T, or it may refer to a field or method f of a nested embedded field of T. The number of embedded fields traversed to reach f is called its depth in T. The depth of a field or method f declared in T is zero. The depth of a field or method f declared in an embedded field A in T is the depth of f in A plus one.
The following rules apply to selectors:
For a value x of type T or *T where T is not a pointer or interface type, x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal.

@TutiFrouti
Copy link
Author

@adonovan I'm talking about the rules for adding methods of the embedded fields to the method set of the structure we're embedding into. It is not related to the selectors nor illegal selector expressions.

@adonovan
Copy link
Member

I'm talking about the rules for adding methods of the embedded fields to the method set of the structure we're embedding into.

The spec calls this process "promotion".

It is not related to the selectors nor illegal selector expressions.

In fact it is. The method set of the outer struct type is the set of method selectors x.f that are legal, and the rules for promotion determine what is legal. For example, "x.f denotes the field or method at the shallowest depth in T where there is such an f. If there is not exactly one f with shallowest depth, the selector expression is illegal."

@TutiFrouti
Copy link
Author

TutiFrouti commented Sep 20, 2024

@adonovan Amazing explanation, thanks. Unfortunately, it is not explained in that way in the specification. Perhaps the following should be included in the specification, it's very clear and useful (I cite you):

The method set of the outer struct type is the set of method selectors x.f that are legal, and the rules for promotion determine what is legal.

EDIT: Nvm, I found something similar:

A field or method f of an embedded field in a struct x is called promoted if x.f is a legal selector that denotes that field or method f.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants