-
Notifications
You must be signed in to change notification settings - Fork 17.7k
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
proposal: spec: Allow interfaces to be inferrable generic types #69822
Comments
In your example func f[T any]() {}
func _() {
f() /* ERROR "cannot infer T" */
} why is inferring If It's not clear what the proposal actually is. A single example doesn't make a proposal. |
@griesemer right, so as of practical use, in my project I have a generic function which returns a struct with that generic. That struct would return a different response, one of which is the generic type. Here's a simple code example. func Build[T any]() Response[T] { panic(0) }
type Response[T any] struct {}
func (Response[T]) As() T { panic(0) }
func (Response[T]) AsMap() map[string]any { panic(0) }
func (Response[T]) AsString() string { panic(0) }
func main() {
Build().AsString() // ERROR: cannot infer T
} Some of the responses don't need the generic type, but the method |
Oh, there's another example from the Reddit post package main
import (
"fmt"
"golang.org/x/exp/slices"
)
// equal is simply ==.
func equal[T comparable](v1, v2 T) bool {
return v1 == v2
}
func main() {
s1 := []int{11, 22, 33}
s2 := []int{11, 22, 33}
// fmt.Println(slices.EqualFunc(s1, s2, equal)) DOESN'T WORK!!
fmt.Println(slices.EqualFunc(s1, s2, equal[int]))
} |
@glossd |
@fzipp right, sorry, I forgot it's an old post |
Another potential problem with this proposal is that not every constraint interface is allowed outside of constraint position. Without something like #57644, it would be irregular that this inference can only succeed if the constraint is permitted as an ordinary interface. |
Change https://go.dev/cl/618855 mentions this issue: |
If you infer |
@DeedleFake that's a good point, you'd want |
@findleyr zoomed in on the essence of this proposal. The idea is that if there are no type arguments (or no "constrained" arguments - see below), a correct and most relaxed argument type is the type parameter constraint itself. And, in the general case, inference would compute the (type set) intersection of the provided (= "constrained") type argument and the respective constraint. This would allow more powerful inference. We have dicussed such an approach internally in the past. It seems conceptually not difficult, but possibly non-trivial to implement (for one, we don't have a general type set intersection mechanism implemented), and the devil is in the details. It's also not clear that it will make a big difference in practice. Our "intersection" mechanism at this point is very simple: we just use the argument type if present, or the constraint type if its core type is a single type. And, as @findleyr mentioned, this all would require that generalized interfaces can be used as value types, not just constraint types. |
If have I think the cases where it should be an error if the type parameter is not specified outweigh the cases where we should default to the type constraint. |
To add to @ianlancetaylor, @findleyr and @griesemer this can be subtly wrong. The typeset of Compared to the other example (Even if conceptually we could consider it also to be the cross product of slice typeset and any typeset to compute the constraints sets implemented and satisfied by If every type was comparable and assertable, basically implementing all the operations of an interface type, we could consider it. (that would also require to assert interfaces to nil type instead of comparing them to nil, it would be another language). So everything works as intended here. |
@ianlancetaylor Yes, it seems to be more important to fail than infer. I'm going to close the issue |
Go Programming Experience
Experienced
Other Languages Experience
Java, JS
Related Idea
Has this idea, or one like it, been proposed before?
It's been asked on Reddit once.
Does this affect error handling?
No
Is this about generics?
Yes
Proposal
I don't understand why
type interface
isn't automatically inferred.This is a literal example of the error code CannotInferTypeArgs
To understand the problem I decided to play around with the Go compiler and, surprisingly, made it work. I sent the changes for review
For this demonstration, I limited the number of TypeParam to only 1 for a possible infer, because I can see how it can complicate things in cases such as
f[T any, S [T]](){}
. I also limited the interface type to a basic oneIf you consider having interfaces as inferrable generics, I'll be happy to contribute. First improvement is to allow multiple generic parameters to be inferred. My idea is to only infer the generic type if it's not used in any other generic parameters. Then it would sound good.
I'd be happy to hear any feedback.
Thank you for your time.
Language Spec Changes
The Go compiler would allow the type interface to be inferred.
Informal Change
This code compiles
This one doesn't
It'd be great to infer
T
asany
Is this change backward compatible?
Yes, because now you'd have to specify the interface for code to compile.
Orthogonality: How does this change interact or overlap with existing features?
It expands the types for inferrable generics.
Would this change make Go easier or harder to learn, and why?
Yes. Not specifying generics when you don't need to is an improvement
Cost Description
I assume only an
if
block in theinfer
function.Changes to Go ToolChain
src/cmd/compiler
Performance Costs
As far as I see now, the final solution would have O(n) for generic parameters, which are in 99% of cases less than 3
Prototype
https://go-review.googlesource.com/c/go/+/618855
The text was updated successfully, but these errors were encountered: