Skip to content
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: Go 2: spec: always permit comparisons against zero value of type #26842

Open
jimmyfrasche opened this issue Aug 7, 2018 · 5 comments
Open

Comments

@jimmyfrasche
Copy link
Member

@jimmyfrasche jimmyfrasche commented Aug 7, 2018

Go, effectively, has three-kinds of comparability:

  • incomparable, there is no == operator defined for a type (structs and arrays with incomparable fields).
  • 0-comparable, there is an == operator but it can only test against the zero value (funcs, maps, and slices can be compared against nil). The spec treats these as incomparable types and notes the special case.
  • comparable, there is an == operator and it works for all values

When writing code with known types, this is not an issue. You know if there's an == operator and whether you can compare against all values or just the zero value.

When generating code (or, possibly in the future, writing generic code) over arbitrary types, this asymmetry is a bit more bothersome. You can't just classify types as comparable or incomparable, you need to handle the 0-comparable case as well even though it is so similar: https://play.golang.org/p/JOmxaVJoYtT

I propose collapsing incomparable and 0-comparable. Allow incomparable structs and arrays to be compared to their zero value. There would always be an == operator and it would always be safe to compare any value to zero. Care would still need to be taken to ensure comparability when using == between arbitrary values, but the simpler classification eases matters.

I believe this would be a 100% backwards-compatible change and perhaps even simplify the spec a bit (or at least not require too many changes).

The concerns would be go/types and reflect, but they both seem to lump what I call 0-comparability in with incomparability, but there, admittedly, could be subtler implications.

This is tangentially related to defining a universal zero value #19642 (comment) in that similar arguments are involved and the two would compliment each other.

@gopherbot gopherbot added this to the Proposal milestone Aug 7, 2018
@gopherbot gopherbot added the Proposal label Aug 7, 2018
@ianlancetaylor ianlancetaylor changed the title proposal: spec: Simplify comparability proposal: Go 2: spec: always permit comparisons against zero value of type Aug 7, 2018
@cherrymui
Copy link
Contributor

@cherrymui cherrymui commented Aug 8, 2018

Does the zero value need to be static? Or it can be dynamic, as long as at run time, at the point of ==, the value is zero?

From https://play.golang.org/p/JOmxaVJoYtT,

	// var zero t
	// fmt.Println(a == zero)

it seems to suggest that the zero value does not have to be static (it is a variable). What if the value is not zero, then? Panic?

@jimmyfrasche
Copy link
Member Author

@jimmyfrasche jimmyfrasche commented Aug 8, 2018

One side would need to be known to be zero statically. Having a universal zero like in the linked issue would be the easiest way to achieve that.

@ndyakov
Copy link

@ndyakov ndyakov commented Nov 30, 2018

Let's look at time.Time.
There is a IsZero function that will show you if the time is empty or not. With your suggestion I think that there should be an interface for structs and only if the struct is implementing that interface it can be checked against zero. For example if you have:

t := time.Time{}
fmt.Println(t == zero) 

It should be transferred to something like

var t time.Time
fmt.Println(t.IsZero())

This is not the same as t == nil, although t == nil doesn't make sense.

@jimmyfrasche
Copy link
Member Author

@jimmyfrasche jimmyfrasche commented Mar 1, 2020

As mentioned in #35966, another solution would be a zero(T) bool builtin that worked for all T, which would be an option should no universal zero value be added.

@carlmjohnson
Copy link
Contributor

@carlmjohnson carlmjohnson commented Mar 2, 2020

A related issue is that you can't define a const which is a nil func/slice because you can't define const func/slices:

	const zero func() = nil // does not compile

So, as of now, the only way to write f == nil is f == nil, since variables aren't statically nil and you can't make a constant nil other than n-i-l.

I think generics will require Go to either add an isZero() generic built-in or a "universal zero" identifier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
6 participants
You can’t perform that action at this time.