Closed
Description
What version of Go are you using (go version
)?
https://go.dev/play/p/Ztyu2FJaajl go1.20.1
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env
)?
Go Playground server
What did you do?
package main
type A[T any, U ~T] struct{}
type B[T any, U ~T | ~*T] struct{}
type C[T any] interface{ ~T | ~*T }
func main() {}
What did you expect to see?
no error
What did you see instead?
./prog.go:3:18: type in term ~T cannot be a type parameter
./prog.go:4:18: type in term ~T cannot be a type parameter
./prog.go:5:27: type in term ~T cannot be a type parameter
Go build failed.
Too bad Google isn't using numbered sections in the Go spec, that would make it easier to cite precise specification items.
So constraints are interfaces and implicitly converted to them using the syntax of the first four examples. The spec states that "An interface type T
may not embed a type element that is, contains, or embeds T
, directly or indirectly." However, we're specifying a type with T as an underlying type. If I read the specification correctly then this should be legal.
It's probably a separate issue with the specification that a constraint of type A[T any, U T | *T] struct{}
is not legal.
Metadata
Metadata
Assignees
Type
Projects
Milestone
Relationships
Development
No branches or pull requests
Activity
ianlancetaylor commentedon Feb 21, 2023
In https://go.dev/ref/spec#Interface_types the spec says "In a term of the form ~T, the underlying type of T must be itself, and T cannot be an interface." Perhaps it should also say that T can't be a type parameter.
CC @griesemer
[-]Unable to create constraint based upon type parameter: "type in term ~T cannot be a type parameter"[/-][+]spec: unable to create constraint based upon type parameter: "type in term ~T cannot be a type parameter"[/+]griesemer commentedon Feb 22, 2023
The underlying type of a type parameter is an interface, namely the constraint interface (see https://golang.org/ref/spec#Underlying_types). So I think what the spec says is accurate. But the fact that the underlying type of a type parameter is an interface is an esoteric aspect of the type system/spec and perhaps needs to be rethought or communicated better.
Re: the numbering of spec sections: it's not a bad idea but requires some tooling so that the spec's numbering and compiler errors don't get out of sync. That said, as of Go 1.20 the compiler internally uses unique IDs for all errors, but they are not yet communicated externally. Once they are, it will be easier to map an error to an explanation and the spec.
griesemer commentedon Feb 22, 2023
Similarly,
type A[T any, U T | *T] struct{}
is not permitted because the 2nd type constraint in the type parameter list is syntactic sugar forinterface{ T | *T }
whereT
is a type parameter, and such interface elements are not permitted for now (see the rules and examples in https://tip.golang.org/ref/spec#General_interfaces).griesemer commentedon Feb 22, 2023
I'm going to close this because it appears that the spec actually has examples illustrating and explaining that the code alluded to in this issue is not permitted.
pPanda-beta commentedon Dec 2, 2023
@griesemer
I think we should re-consider this issue and figure out some way to enable type constraints. Type constraints are important to write compile time type safe programs.
Consider the following utility
Now the following code works.
But this one fails due to no compile time type safety.
Full example: https://go.dev/play/p/SMnrbnv-q0k
Hence if we can somehow make type constraints, i.e.
[T I, I any]
T satisfies I, then we can prevent two thingsany
, and thenany
to I.string
does not satisfyfmt.Stringer
)griesemer commentedon Dec 4, 2023
I don't see how your example is connected to this issue.
I also don't see why your example should be workable: a
string
is notfmt.Stringer
.Garciat commentedon May 16, 2024
If we could use type parameters as constraints, we could leverage 'type relation witnesses' to work around the current limitation that methods may not be generic (or add constraints).
pPanda-beta commentedon May 18, 2024
@griesemer
Because there is not type constraint like c++/java/kotlin, only runtime casting is available today in golang.
Correct and that was my point. I had mentioned "But this one fails due to no compile time type safety." means go compiler should tell me that "string is not fmt.Stringer", not go runtime.
In short we want
type IfaceSlice[T ~I, I any] []T
or justtype IfaceSlice[T I, I any] []T
we can easily ask compiler to checkifs := IfaceSlice[string, fmt.Stringer](a)
and validated that it is impossible.In last comment @Garciat explained this exact problem in that example.
daniel-santos commentedon May 19, 2024
@griesemer, the bug title starts with "spec:" and while I could be mistaken, I believe that is what I originally entered as the title (I won't swear to it). So to close using the reasoning that the compiler behaves per-spec seems to be in bad faith. Please correct me if I'm missing something.
I've been programming for 40 years now (yikes, I'm getting old!) and I know a little bit about languages, compiling, intermediate representations, etc. (the last two probably not as well as @ianlancetaylor), and I say that the specification needs some serious work to make this a "real" language feature and not just something munged on to the side.
It could be something very powerful, but right now it isn't. Kindly re-open this bug report.
PS: The worst time to find out that your code fails due to the lack of type safety is when it occurs in a seldom-used branch of your code. This isn't acceptable for any important program, so it sort-of rules out the use of templates there.
Garciat commentedon May 19, 2024
@daniel-santos: I think @griesemer's POV is that the issue raised seems to be a bug report against the spec; and the spec does mention this use of type parameters. So there's nothing to be done here.
Perhaps we should frame this as a feature request against the spec. (And do so in a new issue; as to 'reset' the context of the conversation.)
Garciat commentedon May 19, 2024
The specific issue that I brought up in my code snippet actually relates more closely to #47127.
ianlancetaylor commentedon May 19, 2024
@daniel-santos Are you saying that the spec and the compiler disagree, or are you saying that the language should change? I thought you were saying the former, in which case it is not bad faith to close the issue saying that in fact the spec and the compiler do agree.
If you are saying that the spec, and the language, should change, then you should file a language change proposal. Thanks.