Skip to content

Generics comparable is allowed non-comparable interfaces #49584

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

Closed
Code-Hex opened this issue Nov 15, 2021 · 6 comments
Closed

Generics comparable is allowed non-comparable interfaces #49584

Code-Hex opened this issue Nov 15, 2021 · 6 comments

Comments

@Code-Hex
Copy link

Code-Hex commented Nov 15, 2021

What version of Go are you using (go version)?

$ go version
go version devel go1.18-c2397905e0 Sat Nov 13 03:33:55 2021 +0000 darwin/arm64

Does this issue reproduce with the latest release?

No, because it includes generics

What operating system and processor architecture are you using (go env)?

Whatever the go playground runs on

What did you do?

Wrote simple function.

func Equal[T comparable](v1, v2 T) bool {
	return v1 == v2
}

func main() {
	v1 := interface{}(func() {})
	v2 := interface{}(func() {})
	Equal(v1, v2)
}

https://gotipplay.golang.org/p/tbKKuehbzUv

What did you expect to see?

Expected to be a compile-time error.

Currently, only the runtime can determine if an argument is not comparable or not. Therefore, to avoid the panic problem, we need to use the reflect package to check whether the two arguments are not comparable or not.

https://gotipplay.golang.org/p/CjLK9zrE1kw

generics code with reflect
import "reflect"

func Equal[T comparable](v1, v2 T) bool {
	if !reflect.TypeOf(v1).Comparable() {
		return false
	}
	if !reflect.TypeOf(v2).Comparable() {
		return false
	}
	return v1 == v2
}

func main() {
	v1 := interface{}(func() {})
	v2 := interface{}(func() {})
	Equal(v1, v2)
}

If we have to rely on the reflect package, I think this is similar to

https://gotipplay.golang.org/p/Eyp49Gq83n4

code without generics
import "reflect"

func Equal(v1, v2 interface{}) bool {
	if !reflect.TypeOf(v1).Comparable() {
		return false
	}
	if !reflect.TypeOf(v2).Comparable() {
		return false
	}
	return v1 == v2
}

func main() {
	v1 := interface{}(func() {})
	v2 := interface{}(func() {})
	Equal(v1, v2)
}

What did you see instead?

panic: runtime error: comparing uncomparable type func()

goroutine 1 [running]:
main.Equal[...](...)
	/tmp/sandbox3783883907/prog.go:4
main.main()
	/tmp/sandbox3783883907/prog.go:10 +0x2e
@Code-Hex Code-Hex changed the title Generics comparable is allowed not comparable interfaces Generics comparable is allowed non-comparable interfaces Nov 15, 2021
@choleraehyq
Copy link
Contributor

From spec:

Interface values are comparable. Two interface values are equal if they have identical dynamic types and equal dynamic values or if both have value nil.

@Code-Hex
Copy link
Author

@choleraehyq Yes. That's the point.
If we don't check the underlying, I think the comparable type is almost the same as the any type.

@choleraehyq
Copy link
Contributor

@Code-Hex Compiler doesn't know the underlying type of an interface value at compile time.

@Code-Hex
Copy link
Author

@choleraehyq I understand. However, I don't think it's a good idea to rely on the reflect package to avoid panic.

@Code-Hex
Copy link
Author

The problem is that when we use generics, we are not likely to write code for panic.
The code is from slices package.
https://gotipplay.golang.org/p/BJFpRRTo5sK

I believe that We are in a state where I can easily cause a panic. If there is a way to avoid this, I will be happy.

@randall77
Copy link
Contributor

This is working as expected. T in this code is instantiated with interface{}, which is comparable, so the compiler cannot report an error.

This code correctly fails at compile time, because T is trying to be instantiated with func():

func main() {
	v1 := func() {}
	v2 := func() {}
	Equal(v1, v2)
}

There is no expectation that Equal[interface{}] and an explicit non-generic func EqualInterface(v1, v2 interface{}) bool { return v1==v2 } behave any differently. If they did that would be strange.

I'm going to close this issue as untenable given the current generics design. Feel free to submit a change proposal if you or someone else has a concrete idea about what they would like to change.

@golang golang locked and limited conversation to collaborators Nov 15, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

4 participants