reflect: Value.Comparable returns false for nil interface value
Go version
go1.22.0.linux-amd64
Output of go env in your module/workspace:
GO111MODULE=''
GOARCH='amd64'
GOBIN=''
GOCACHE='/home/user/.cache/go-build'
GOENV='/home/user/.config/go/env'
GOEXE=''
GOEXPERIMENT=''
GOFLAGS=''
GOHOSTARCH='amd64'
GOHOSTOS='linux'
GOINSECURE=''
GOMODCACHE='/home/user/go/pkg/mod'
GONOPROXY=''
GONOSUMDB=''
GOOS='linux'
GOPATH='/home/user/go'
GOPRIVATE=''
GOPROXY='https://proxy.golang.org,direct'
GOROOT='/usr/local/go'
GOSUMDB='sum.golang.org'
GOTMPDIR=''
GOTOOLCHAIN='auto'
GOTOOLDIR='/usr/local/go/pkg/tool/linux_amd64'
GOVCS=''
GOVERSION='go1.22.0'
GCCGO='gccgo'
GOAMD64='v1'
AR='ar'
CC='gcc'
CXX='g++'
CGO_ENABLED='1'
GOMOD='/home/user/myproject/go.mod'
GOWORK='/home/user/myproject/go.work'
CGO_CFLAGS='-O2 -g'
CGO_CPPFLAGS=''
CGO_CXXFLAGS='-O2 -g'
CGO_FFLAGS='-O2 -g'
CGO_LDFLAGS='-O2 -g'
PKG_CONFIG='pkg-config'
GOGCCFLAGS='-fPIC -m64 -pthread -Wl,--no-gc-sections -fmessage-length=0 -ffile-prefix-map=/tmp/go-build2649934156=/tmp/go-build -gno-record-gcc-switches'
What did you do?
I'm trying to check in the runtime if I can use a value as a key in a map. I'm using reflect.Value.Comparable() to determine whether a value is comparable or not. Example: https://go.dev/play/p/3p7t501BqSU
What did you see happen?
It says my struct isn't comparable, but I still can use it as a key in a map or compare it with other structs.
What did you expect to see?
If this is something that's intended, then at least name of reflect.Value.Comparable() function could be more accurate. Otherwise, I expect this function to return true for any type that can be compared or used as a key for a map.
I think that it boils down to this:
https://github.com/golang/go/blob/48d899dcdbed4534ed942f7ec2917cf86b18af22/src/reflect/value.go#L3415-L3416
Simpler reproducer:
var val any = nil
v := reflect.ValueOf(&val).Elem().Elem()
fmt.Println(v.Comparable()) // false
var val any = 5
v := reflect.ValueOf(&val).Elem().Elem()
fmt.Println(v.Comparable()) // true
EDIT: See https://github.com/golang/go/issues/65718#issuecomment-1948167005
@donwitobanana does the comment by @mateusz834 answer your question?
I think nil interface value should probably be considered comparable.
@thanm the comment by @mateusz834 provides simpler reproducer, but unfortunately doesn't answer the question. The concern if this should be considered "comparable" is still valid.
@mateusz834's reproducer is not correct. The following is the correct one:
package main
import "reflect"
func main() {
var a any
v := reflect.ValueOf(&a).Elem()
println(v.Comparable(), a == a) // false true
}
This is certainly a bug, because reflect result should be consistent with non-reflect one..
@go101 Yeah, thanks for catching this
Change https://go.dev/cl/564795 mentions this issue: reflect: make Value.Comparable return true for nil interface value