Repository navigation
proposal: spec: type inference for union of functions #61802
Description
Activity
even if the type could be inferred: you'd run into https://go.dev/play/p/9KP_p3VGEVl
./prog.go:23:15: invalid operation: cannot call non-function fn (variable of type Fn constrained by Func[In, Out])
which makes sense: within your generic function, you have no way of distinguishing between needing to call
fn(in)andfn(ctx, in)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.
- changed the title
[-]proposal: Support type inference on functions that accept type constraints[/-][+]proposal: spec: type inference for union of functions[/+]on Aug 8, 2023 - addedTypeInferenceIssue is related to generic type inferenceIssue is related to generic type inference
on Aug 8, 2023 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.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsIncoming
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 aFuncconstraint: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!