-
Notifications
You must be signed in to change notification settings - Fork 17.9k
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
cmd/compile: clarify prose/examples regarding struct identity when embedded types match equally named non-embedded fields #69472
Comments
A clever finding. BTW, it looks your code doesn't prove type identity, but conversion rules. Though I believe that your point is described well and it applies to conversions too. |
The code is used to prove type identity:
|
@zigo101 Right, I just used conversion as a quick way to check type identity equality. According to specification if two types are identical, values of these types can be assigned to each other. Further, if they are assignable, conversion is possible. |
As I understand the spec, in case of (3) and (4), M1 and M2 does not have the same sequence of fields, because MyType1 of M1 is an embedded field, while MyType1 of M2 is not. These fields have the same name but are different fields. |
BTW, if I use a @zigo101 way of checking type identity, then even the first example fails (it prints @cuonglm Specification doesn't make a distinction between embedded and ordinary fields. From spec:
Even if you are right, then the first example with |
The problem shown in the first example should be implementation bug in my understanding. |
I don't get it. You can't do |
Don't that your quote show the difference? "act like" does not mean they are the same fields, causing M1 and M2 don't have the same sequence of fields |
Aha, @cuonglm is right here. [edit] When they are alias declarations, then |
Then how is conversion possible? |
It's the same manner with converting from a float to a int, following a set of rules, which you can read here: https://go.dev/ref/spec#Conversions |
Because in example 1, The point (inaccuracy in spec) mentioned by @leabit can still be demonstrated in this example: #69472 (comment) |
As I explained above, M1 and M2 don't have the same sequence of fields. If you laid them out literally,
while
They don't satisfy the type identity definition in spec:
|
Okay, I think it is indeed some nitpicking.
The final |
@cuonglm Yes, you are right about the first example (my bad, I forgot they are named in main, not aliases like in
However, I think the inconsistency still exists for the rest (examples 3 and 4). For me If you look at it that way, then the following should print
|
How could they be different? These fields are both embedded, have the same name MyType1, and have the same underlying type struct{}. The package pac1 and pac2 does not play any role in this identity checking because MyType1 is a exported field. |
@leabit In you last example, The core of the issue is whether or not |
@cuonglm Well, the specification treats the following two as the same in all segments: Just to be clear, I fully understand what you are trying to say and you might be right (we are in the same team :D ), but something is wrong here, and it's either the ambiguity and vagueness of the specification or maybe implementation. If you are right, it must be clearly stated in the specification and your "As I understand the spec..." says that it is not. |
@zigo101 It states:
I don't see any difference here between embedded and ordinary fields. A struct is a sequence of named elements (field sequence), where the name can be implicit (embedded field) or explicit. So according to it Specification for type identity states:
and they definitely have (it's just whether you specified name explicitly or field got a name implicitly). |
I agree it is not very clear. Maybe the wording can be improved. |
@zigo101 Yes, or implement it in a way it doesn't make a difference between embedded and ordinary field (as specification states, in my interpretation and understanding). Anyway, something must be done, whether it involves fixing the compiler or updating the specification. At least, we can all agree that the problem exists. |
Then the "embedding field" feature will totally lost its meaningfulness. :D |
@zigo101 I meant, in this case. Not generally (not like losing promotion of methods). |
Promoted fields/methods are intrinsic characters of a type. If two types have different promoted fields/methods, then they must be two distinct types. |
@zigo101 You are talking about the following?
Both I assume, then the conclusion is that the specification is not good (and needs improvement) since according to it, these two types are the same. |
The spec intends to view For this specific case in 3rd and 4th examples of your first comment, a.k.a. the case in which the embedding fields don't provide promoted fields/methods, it might be okay to treat the containing unnamed struct types as identical, but I don't think it is worth making this difference from embedding fields providing promoted fields/methods. |
It's not clear to me what this issue has to do with alias or unnamed types: if I understand correctly, the issue is about whether two struct fields are identical if one of them is embedded and the other one is not but they appear in the same "spot" in the struct, have the same name, same type, and same tag. It is the intent of the spec that two corresponding fields are not identical if one of them is embedded and the other one is not. I agree that this doesn't seem to be spelled out explicitly. A suitable example or perhaps some prose fine tuning should address that. The implementation is very clear though: for two structs to be identical, two otherwise matching fields must be both embedded or both not embedded. |
Change https://go.dev/cl/616697 mentions this issue: |
Named types are different without any further check, so issue only makes sense when unnamed types are used. First example would fail to compile in case
Types of the field in
Yes, you did understand it correctly. |
Go version
go version go1.23.0 linux/amd64
Output of
go env
in your module/workspace:What did you do?
Golang specification for type identity states the following for the struct types:
Thus, it has 4 requirements:
However, there are cases related to embedding aliases of unnamed types where, despite meeting all four previous requirements, the compiler still fails to compile.
I will explain the problem through few examples. The following notes holds for all examples:
pac1
,pac2
andmain
pac
andpac2
are unnamed typesstruct{}
(thus, they are identical)(1) This example successfully compiles (as expected).
M1
andM2
have the same sequence of fields. Names, even thought not explicitly defined, are indirectly given by embedding and thus they are same (MyType1
). Types of the fields (fieldMyType1
) are also same (struct{}
).pac1
:pac2
:main
:(2) In this example
MyType1 = struct{}
is replaced withMyType2 = struct{}
inpac2
. Also,pac2.MyType2
is now embedded inM2
(instead ofpac2.MyType1
) inmain
package. As expected, it doesn't compile. Even thought the types of the fields are the same, the names are not (MyType1
!=MyType2
), thus requirement 2 doesn't hold.pac1
:pac2
:main
:(3) This example shows the actual problem. The only difference compared to the previous example is that embedded field (
pac2.MyType2
) is now replaced by non-embedded (ordinary) field with the nameMyType1
(type is the same). Since specification for type identity doesn't make a distinct between embedded and ordinary field in the struct this should be valid and compile (all requirements are met).pac1
:pac2
:main
:(4) This example just shows that even when
MyType1 pac2.MyType2
is replaced withMyType1 pac1.MyType1
inM2
(so just the name is added), it still doesn't compile.pac1
:pac2
:main
:What did you see happen?
Inconsistency between specification and implementation
What did you expect to see?
Since I am following specification, I expect examples (3) and (4) to compile, or to modify the specification to address the difference.
The text was updated successfully, but these errors were encountered: