You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Background: Go 1.22's go/types defined new API for materialized alias types, as a step towards generic alias types. Alias has two operations: Underlying, which removes all Alias and Named constructors, recursively, returning the representation type; and Unalias, which removes only Alias constructors, again recursively, returning the first non-alias type. (A judicious sprinkling of Unalias operations throughout existing code is the minimal change to keep most existing go/types clients working.)
However, the API provides no way to remove a single Alias constructor. That means, for example, that there is no way for a client of go/types, given the types for:
typeA=BtypeB=int
to write a function that prints "type A = B" (without calling the existing ObjectString method). More importantly, import/export tools are unable to preserve the structure of the original types.
(Unalias is nonetheless useful, and Underlying is of course a requirement of the Type interface, but Alias types are not isomorphic to defined types in the way that, given type A B; type B int, the spec defines the underlying type of A as int, and otherwise stipulates no relationship between A and B.)
Proposal: We add an Alias.RHS accessor method, which removes exactly one Alias constructor. So, Alias.RHS(A) would return B.
changed the title [-]proposal: go/types: add Alias.RHS accessor, which removes exactly one Alias constructor[/-][+]proposal: go/types: add Alias.Rhs method[/+]on Mar 27, 2024
This proposal has been added to the active column of the proposals project
and will now be reviewed at the weekly proposal review meetings.
— rsc for the proposal review group
Seems fine but we already spell it Rhs in other places, so we should do the same here.
I'm not convinced: Rhs is not idiomatic spelling, and ast.AssignStmt.Rhs is essentially unrelated to types.Alias.RHS (you wouldn't plumb one through to the other, for example) so I don't see any downside to using the correct capitalization.
The downside is that I am a gopher of very little brain, and I will never remember when to use Rhs and when to use RHS.
The general rule is spell the same words the same way, so my brain can remember other things instead.
I'm not opposed, but I don't really follow the argument that Aliases are fundamentally different from Named types here. If we want to be able to print type A = B, why would we not also want to be able to print type A B? Isn't the question whether we preserve (and expose) the syntactic relationship in the type system?
Historically, we've intentionally avoided preserving inessential syntax in types, with Interface embeddings being the one notable exception. In fact, I think this philosophy is why we didn't have an Alias type in the first place.
Can we clarify our philosophical approach? Have we decided that it's generally a good idea to preserve the syntax of type definitions in the type system? If so, should we add Named.Rhs?
Is this proposal also suggesting that we change the String value of an Alias? If so, we could of course do that without also exposing the Rhs accessor (though that would be inconsistent).
I don't really follow the argument that Aliases are fundamentally different from Named types here.
The main motive is that transiting export data should not make material changes to types, as this would cause tools like gopls to display different behavior depending on whether it obtained the types from a cache of export data or from type-annotated syntax. In the case of type A = B, the string representation shows the RHS type as declared; if the exporter were forced to use Unalias, then the reimported type would be type A = int, which would be confusing and even nondeterministic.
By contrast, Named types do not reveal their middlemen in their API or their printed representation. (You raise an interesting question as to whether we would be better off if they did, but I don't think we need to address it now. IMHO the more troublesome difficulty with named types is not being able to distinguish A.f from B.f in type A B; type B struct{f int}, but we can't fix that.)
Is this proposal also suggesting that we change the String value of an Alias?
Got it. So the problem is that there is an observable behavior of Aliases (their current type string) that can't be preserved through import. I agree that this needs to be fixed. I also agree that the behavior of showing the RHS in the type string is correct.
We can worry about philosophy with respect to Named types later.
Activity
gopherbot commentedon Mar 27, 2024
Change https://go.dev/cl/574716 mentions this issue:
go/types: ObjectString: remove only 1 Alias for "type A = RHS"rsc commentedon Mar 27, 2024
Seems fine but we already spell it Rhs in other places, so we should do the same here.
[-]proposal: go/types: add Alias.RHS accessor, which removes exactly one Alias constructor[/-][+]proposal: go/types: add Alias.Rhs method[/+]rsc commentedon Mar 27, 2024
This proposal has been added to the active column of the proposals project
and will now be reviewed at the weekly proposal review meetings.
— rsc for the proposal review group
adonovan commentedon Mar 27, 2024
I'm not convinced: Rhs is not idiomatic spelling, and ast.AssignStmt.Rhs is essentially unrelated to types.Alias.RHS (you wouldn't plumb one through to the other, for example) so I don't see any downside to using the correct capitalization.
ianlancetaylor commentedon Mar 27, 2024
Note that
go/types.Initializeralso spells itRhs.That is, it seems like we shouldn't use two different spellings in the same package.
rsc commentedon Mar 28, 2024
The downside is that I am a gopher of very little brain, and I will never remember when to use Rhs and when to use RHS.
The general rule is spell the same words the same way, so my brain can remember other things instead.
findleyr commentedon Mar 28, 2024
I'm not opposed, but I don't really follow the argument that Aliases are fundamentally different from Named types here. If we want to be able to print
type A = B, why would we not also want to be able to printtype A B? Isn't the question whether we preserve (and expose) the syntactic relationship in the type system?Historically, we've intentionally avoided preserving inessential syntax in types, with Interface embeddings being the one notable exception. In fact, I think this philosophy is why we didn't have an Alias type in the first place.
Can we clarify our philosophical approach? Have we decided that it's generally a good idea to preserve the syntax of type definitions in the type system? If so, should we add
Named.Rhs?Is this proposal also suggesting that we change the
Stringvalue of an Alias? If so, we could of course do that without also exposing theRhsaccessor (though that would be inconsistent).adonovan commentedon Mar 28, 2024
OK, Rhs is is.
The main motive is that transiting export data should not make material changes to types, as this would cause tools like gopls to display different behavior depending on whether it obtained the types from a cache of export data or from type-annotated syntax. In the case of
type A = B, the string representation shows the RHS type as declared; if the exporter were forced to use Unalias, then the reimported type would betype A = int, which would be confusing and even nondeterministic.By contrast, Named types do not reveal their middlemen in their API or their printed representation. (You raise an interesting question as to whether we would be better off if they did, but I don't think we need to address it now. IMHO the more troublesome difficulty with named types is not being able to distinguish A.f from B.f in
type A B; type B struct{f int}, but we can't fix that.)No.
findleyr commentedon Mar 28, 2024
Got it. So the problem is that there is an observable behavior of Aliases (their current type string) that can't be preserved through import. I agree that this needs to be fixed. I also agree that the behavior of showing the RHS in the type string is correct.
We can worry about philosophy with respect to Named types later.
8 remaining items
gopherbot commentedon Apr 24, 2024
Change https://go.dev/cl/581615 mentions this issue:
go/types: add Alias.Rhsgopherbot commentedon Apr 24, 2024
Change https://go.dev/cl/581635 mentions this issue:
internal/gcimporter: use Alias.Rhs, not unsafe hackgo/types: add Alias.Rhs
internal/gcimporter: use Alias.Rhs, not unsafe hack