-
Notifications
You must be signed in to change notification settings - Fork 18.5k
Open
Labels
ProposalProposal-HoldTypeInferenceIssue is related to generic type inferenceIssue is related to generic type inferencegenericsIssue is related to genericsIssue is related to generics
Milestone
Description
What version of Go are you using (go version)?
$ go version 1.18
Does this issue reproduce with the latest release?
Yes
What operating system and processor architecture are you using (go env)?
go env Output
$ go env GO111MODULE="auto" GOARCH="arm64" GOBIN="" GOCACHE="/Users/changkun/Library/Caches/go-build" GOENV="/Users/changkun/Library/Application Support/go/env" GOEXE="" GOEXPERIMENT="" GOFLAGS="" GOHOSTARCH="arm64" GOHOSTOS="darwin" GOINSECURE="" GOMODCACHE="/Users/changkun/go/pkg/mod" GONOPROXY="" GONOSUMDB="" GOOS="darwin" GOPATH="/Users/changkun/go" GOPRIVATE="" GOPROXY="https://proxy.golang.org,direct" GOROOT="/Users/changkun/goes/go" GOSUMDB="sum.golang.org" GOTMPDIR="" GOTOOLDIR="/Users/changkun/goes/go/pkg/tool/darwin_arm64" GOVCS="" GOVERSION="go1.18" GCCGO="gccgo" AR="ar" CC="clang" CXX="clang++" CGO_ENABLED="1" GOMOD="/Users/changkun/dev/poly.red/polyred/go.mod" GOWORK="" CGO_CFLAGS="-g -O2" CGO_CPPFLAGS="" CGO_CXXFLAGS="-g -O2" CGO_FFLAGS="-g -O2" CGO_LDFLAGS="-g -O2" PKG_CONFIG="pkg-config" GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/g2/6fmr1qzx0ns3shq74zrp6bd40000gn/T/go-build1836918707=/tmp/go-build -gno-record-gcc-switches -fno-common"
What did you do?
https://go.dev/play/p/bW8xjgG0x6Z
In this example, When we use Option1[T] (constrainted by A or B) as
an argument of NewA[T], there is only one possibility to infer the concrete
type of Option1[T], because NewA only accept A as type parameter.
package main
import "fmt"
type A struct{ val int }
type B struct{ val int }
type Option[T A | B] func(v *T)
func NewA[T A](opts ...Option[T]) *T {
a := new(T)
for _, opt := range opts {
opt(a)
}
return a
}
func NewB[T B](opts ...Option[T]) *T {
b := new(T)
for _, opt := range opts {
opt(b)
}
return b
}
func Option1[T A | B](val int) Option[T] {
return func(v *T) {
switch vv := any(v).(type) {
case *A:
vv.val = val
case *B:
vv.val = val
}
}
}
func main() {
u := NewA(Option1[A](42)) // OK
v := NewB(Option1[B](42)) // OK
// NewA(Option1(42)) // ERROR: cannot infer T
// NewB(Option1(42)) // ERROR: cannot infer T
fmt.Println(u, v) // &{42} &{42}
}What did you expect to see?
It is possible to write code without specifying type parameter in this case:
NewA(Option1(42))
What did you see instead?
Compile error: cannot infer T
More reasons
This is a quite simplification when the options are distributed in a different package, say pkgname:
package pkgname
import "fmt"
type A struct{ val int }
type B struct{ val int }
type Option[T A | B] func(v *T)
func NewA[T A](opts ...Option[T]) *T {
a := new(T)
for _, opt := range opts {
opt(a)
}
return a
}
func NewB[T B](opts ...Option[T]) *T {
b := new(T)
for _, opt := range opts {
opt(b)
}
return b
}
func Option1[T A | B](val int) Option[T] {
return func(v *T) {
switch vv := any(v).(type) {
case *A:
vv.val = val
case *B:
vv.val = val
}
}
}
---
package main
func main() {
pkgname.NewA(pkgname.Option1[pkgname.A](42)) // Feels stutter
pkgname.NewB(pkgname.Option1[pkgname.B](42))
// pkgname.NewA(pkgname.Option1(42)) // Would be much simpler in terms of use and readability
// pkgname.NewB(pkgname.Option1(42))
}au-phiware, shashank-priyadarshi, nilsocket, btsomogyi and sonalysawoo-civarvenil
Metadata
Metadata
Assignees
Labels
ProposalProposal-HoldTypeInferenceIssue is related to generic type inferenceIssue is related to generic type inferencegenericsIssue is related to genericsIssue is related to generics