Description
Go Programming Experience
Experienced
Other Languages Experience
Java, Haskell, Python, C++
Related Idea
- Has this idea, or one like it, been proposed before?
- Does this affect error handling?
- Is this about generics?
- Is this change backward compatible? Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit
Has this idea, or one like it, been proposed before?
Sort of: #47127
Also related: #58590
Does this affect error handling?
No.
Is this about generics?
It relates to type constraints/bounds.
Proposal
Allow type parameters as type bounds:
func cast[T U, U any](t T) U { return t }
Note that this not include things like:
[T ~U, U any]
[T U | int, U any]
[T interface{ U }, U any]
-- maybe we do want to allow this? But syntactically, it opens the floodgates[T interface{ U; V }, U any, V any]
- or any other type expression that is not a single type parameter reference
Language Spec Changes
I don't know exactly how, but some clause in https://go.dev/ref/spec#TypeConstraint would need to be updated.
If [T interface{ U }, U any]
is allowed, then https://go.dev/ref/spec#General_interfaces would need to be updated as well.
Informal Change
No response
Is this change backward compatible?
Yes.
Orthogonality: How does this change interact or overlap with existing features?
No response
Would this change make Go easier or harder to learn, and why?
No response
Cost Description
No response
Changes to Go ToolChain
No response
Performance Costs
No response
Prototype
I prototyped the change in Garciat@c69063f.
Type-checking works as expected:
func cycle[A B, B C, C D, D A]() {} // new error: invalid recursive type parameter constraint
func term[T interface{ U }, U any]() {} // error: term cannot be a type parameter
func cast[T U, U any](t T) U { return t } // OK
type X struct{}
func (_ X) M() {}
func main() {
cast[string, string]("hi") // error: string does not satisfy string (string is not an interface)
cast[X, interface{}](X{}) // OK
cast[X, interface{ M() }](X{}) // OK
cast[X, interface { M(); N() }](X{}) // error: X does not satisfy interface{M(); N()} (missing method N)
}
Compilation also seems to be doing the right thing; the code runs as expected.
However, getting full type parameter embedding in interfaces ([T interface{ U }, U any]
) seems to be a much more involved code change.