-
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
proposal: spec: type inference for union of functions #61802
Comments
even if the type could be inferred: you'd run into https://go.dev/play/p/9KP_p3VGEVl
which makes sense: within your generic function, you have no way of distinguishing between needing to call barring movement on #45380, I think a failure here is expected. |
Thanks for your response. This actually does work today though: package main
import (
"context"
"encoding/json"
"fmt"
"net/http"
)
type Func[In, Out any] interface {
func(in *In) (*Out, error) |
func(ctx context.Context, in *In) (*Out, error)
}
func RPC[In, Out any, Fn Func[In, Out]](fn Fn) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
var in In
switch t := any(fn).(type) {
case func(in *In) (*Out, error):
out, err := t(&in)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := json.NewEncoder(w).Encode(out); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
case func(ctx context.Context, in *In) (*Out, error):
out, err := t(r.Context(), &in)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if err := json.NewEncoder(w).Encode(out); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
})
}
type HelloIn struct {
}
type HelloOut struct {
Out string
}
func Hello(in *HelloIn) (*HelloOut, error) {
return &HelloOut{"without context"}, nil
}
func Hello2(ctx context.Context, in *HelloIn) (*HelloOut, error) {
return &HelloOut{"with context"}, nil
}
func main() {
mux := http.NewServeMux()
mux.Handle("/hello", RPC[HelloIn, HelloOut](Hello))
mux.Handle("/hello2", RPC[HelloIn, HelloOut](Hello2))
fmt.Println("listening on http://localhost:8080")
http.ListenAndServe(":8080", mux)
} $ go run main.go
listening on http://localhost:8080 Then in another terminal: $ curl http://localhost:8080/hello
{"Out":"without context"}
$ curl http://localhost:8080/hello2
{"Out":"with context"} It would definitely be better with #45380, but they're orthogonal proposals. |
seems similar to #61731 |
We currently only do this kind of type inference if the type parameter has a constraint with a core type, which is why the simple case works but the case that permits multiple types does not. It seems pretty complicated to make this work with a constraint with an arbitrary type set. It would seem to introduce a lot of polynomial time algorithms when a value of a type parameter with one constraint is passed to a function that takes a type parameter with a different constraint. If we can figure out a principled and efficient mechanism, then, great. But it's not obvious. See #58650 for more discussion of the kinds of algorithms we can implement. |
Context
Type inference is a powerful feature where Go can infer generic types based on usage. In the following example, the
RPC(Hello)
function is able to infer types based on the function signature.The long-form equivalent is
RPC[HelloIn, HelloOut](Hello)
. This also works with type constraints when you have a single type. In the following example, we introduce aFunc
constraint:Then adjusting the RPC function to the following:
And type inference continues to work as expected.
Problem
If you introduce another type like the following:
Then type inference no longer works. You'll be greeted with:
To fix this, you need to specify the types:
Proposal
It'd be great if type inference could infer more complex types. It does seem to work with basic type constraints, which is awesome:
Could this be extended to support more complex types?
Thanks for your consideration!
The text was updated successfully, but these errors were encountered: