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

reflect: Value.IsZero should report true for negative zero #61827

Closed
dsnet opened this issue Aug 7, 2023 · 10 comments
Closed

reflect: Value.IsZero should report true for negative zero #61827

dsnet opened this issue Aug 7, 2023 · 10 comments

Comments

@dsnet
Copy link
Member

dsnet commented Aug 7, 2023

I discovered this while exploring #61372 (comment).

In that comment, I asked whether v == zero is identical to reflect.ValueOf(&v).Elem().IsZero().
And the answer is unfortunately, "no":

negZero := math.Copysign(0, -1)
negStructZero := struct{ F float64 }{negZero}
negArrayZero := [1]float64{negZero}

fmt.Println(reflect.ValueOf(negZero).IsZero())       // false, should be true if `negZero == zero`
fmt.Println(reflect.ValueOf(negStructZero).IsZero()) // true
fmt.Println(reflect.ValueOf(negArrayZero).IsZero())  // true

The fact that negStructZero and negArrayZero report true is due to a regression I accidentally introduced in CL/411478 and has been live since Go 1.20.

Looking through #7501, there was no discussion how -0 is handled.
In CL/171337, @dsnet and @bradfitz called out how -0 should be handled, but I don't think there was a principled way to think through how it should actually be handled.

We are currently in a state where we are inconsistent.

I propose we make v == zero identical to reflect.ValueOf(&v).Elem().IsZero(),
which means that reflect.ValueOf(negZero).IsZero() should report true.

\cc @ianlancetaylor @rsc @bradfitz

@dsnet dsnet added the Proposal label Aug 7, 2023
@gopherbot gopherbot added this to the Proposal milestone Aug 7, 2023
@ianlancetaylor
Copy link
Contributor

Whoops, I looked at the IsZero code and totally missed this.

@dsnet
Copy link
Member Author

dsnet commented Aug 8, 2023

Noting here: @ianlancetaylor says in #61372 (comment):

The reflect.Value.IsZero method, for a non-comparable struct type, currently checks the value of blank struct fields. I am suggesting that v == zero should not check such fields, because we ignore them in ordinary == comparisons. And perhaps we should change reflect.Value.IsZero to match that.

@rsc
Copy link
Contributor

rsc commented Aug 9, 2023

In the example:

fmt.Println(reflect.ValueOf(negZero).IsZero()) // false, should be true if negZero == zero
fmt.Println(reflect.ValueOf(negStructZero).IsZero()) // true
fmt.Println(reflect.ValueOf(negArrayZero).IsZero()) // true

I think these should all report true. Is that what everyone else thinks too?

@gopherbot
Copy link

Change https://go.dev/cl/517777 mentions this issue: reflect: make Value.IsZero identical to v == zero

@rsc
Copy link
Contributor

rsc commented Aug 9, 2023

This proposal has been added to the active column of the proposals project
and will now be reviewed at the weekly proposal review meetings.
— rsc for the proposal review group

@rsc
Copy link
Contributor

rsc commented Aug 16, 2023

Based on the discussion above, this proposal seems like a likely accept.
— rsc for the proposal review group

@ijschwabacher
Copy link

I might be misunderstanding how generic functions are compiled, but does this mean that the compiler has to track which type arguments are floats so that it can compile the == zero check differently?

Or... what is this supposed to print, once zero is recognized? https://go.dev/play/p/7fT1qQiBUGO?v=gotip

@ianlancetaylor
Copy link
Contributor

does this mean that the compiler has to track which type arguments are floats so that it can compile the == zero check differently?

The compiler already has to use floating-point equality semantics for any use of == if the type argument is a floating-point type. That doesn't change with the introduction of a builtin zero.

@rsc
Copy link
Contributor

rsc commented Aug 30, 2023

No change in consensus, so accepted. 🎉
This issue now tracks the work of implementing the proposal.
— rsc for the proposal review group

@rsc rsc changed the title proposal: reflect: Value.IsZero should report true for negative zero reflect: Value.IsZero should report true for negative zero Aug 30, 2023
@rsc rsc modified the milestones: Proposal, Backlog Aug 30, 2023
@gopherbot
Copy link

Change https://go.dev/cl/524615 mentions this issue: reflect: update IsZero to handle negative and ignore blank fields

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Accepted
Development

No branches or pull requests

6 participants