Object.is()

# Axel Rauschmayer (5 years ago)

The use case for Object.is() that I see is to have a version of ===, as a function, that allows one to detect/search for NaN. For that use case, distinguishing +0 and -0 seems problematic (they are equated almost everywhere else). Should they really be distinguished by Object.is()?

# Alex Kocharin (5 years ago)

I wonder why isn't it ====. Would be funny.

+0 and -0 should be distinguished there. If you don't want them to be, you can always use comparison operators.

# Brendan Eich (5 years ago)

We talked about this at the last last TC39 meeting. I joked about adding Object.isz, or (in honor of @izs) Object.izs. But we didn't add anything. You can write it yourself, of course (just modify the Object.is polyfill).

# Axel Rauschmayer (5 years ago)

We talked about this at the last last TC39 meeting. I joked about adding Object.isz, or (in honor of @izs) Object.izs.

;-)

But we didn't add anything. You can write it yourself, of course (just modify the Object.is polyfill).

My question … is: Wouldn’t Object.is() be more useful if it didn’t distinguish +0 and -0?

# Adam Ahmed (5 years ago)

If anecdotal sharing is valuable...

As a JS web developer, I'd say so. I use isNaN weekly, and have never once had to distinguish +/-0. It may be useful in some very limited cases, but for me Object.is would be much more valuable without it. Having the distinction means that in most cases I won't be able to use Object.is because I want +0 to equal -0.

# Domenic Denicola (5 years ago)

If the thought is that distinguishing +0 and -0 is never useful, then the goal should be to stop distinguishing between them wherever possible.

Currently there are three "strict-ish" equality tests: Strict Equality Comparison (===), SameValueZero, and SameValue (Object.is). We'll leave Abstract Equality Comparison (==) out of this.

  • Strict Equality Comparison is used in case matching, Array.prototype.indexOf, Array.prototype.lastIndexOf, and ===.
  • SameValueZero is used for Maps and Sets, plus something about ArrayBuffer lengths.
  • SameValue is used in many places throughout the spec, especially relating to property values; it is also used for WeakMaps and WeakSets.

Note that most of the uses of SameValue are cases where the input is already guaranteed to be either an object (e.g. prototypes, property descriptor set functions) or a string (property keys). So many of them could be replaced with SameValueZero, or even Strict Equality Comparison, without consequence.

But there are a few cases, e.g. property redefinition, that do distinguish. For example, if you have a non-writable/non-configurable property whose value is -0, then trying to set/redefine that property will fail, since SameValue is used in that test.

If the belief is truly that SameValueZero is more useful than SameValue, perhaps we should consider relaxing that restriction, and allowing people to flip the sign of non-writable zero-valued properties? Indeed, perhaps it would be worth trying to move some of the strict equality comparisons over to SameValueZero, if that doesn't break too many things. I know moving to SameValue has been discussed and rejected in the past, but that was before SameValueZero was baked into the spec.

(I personally dislike the existence of SameValueZero, and would rather stick with SameValue. But I have no reasonable arguments from practicality, only theoretical purity, and so I don't anticipate convincing anyone.)

# Brendan Eich (5 years ago)

Domenic Denicola wrote:

If the belief is truly that SameValueZero is more useful than SameValue, perhaps we should consider relaxing that restriction, and allowing people to flip the sign of non-writable zero-valued properties?

You are reasoning from general to particular, but without any reason to focus on the particular of redefining a non-writable property from -0 to +0 or vice versa. There is no use-case "there" there! I bet Mark would find that a subtle security problem.

Indeed, perhaps it would be worth trying to move some of the strict equality comparisons over to SameValueZero, if that doesn't break too many things.

Who knows? 1JS and browser game theory combine to mean no one will risk trying, only to lose compatibility around the edges.

I know moving to SameValue has been discussed and rejected in the past, but that was before SameValueZero was baked into the spec.

No one is discussing changing === and !==, AFAIK. Not every, in TC39.

(I personally dislike the existence of SameValueZero, and would rather stick with SameValue. But I have no reasonable arguments from practicality, only theoretical purity, and so I don't anticipate convincing anyone.)

We should look at this again. The newest thing is the one to cast a colder eye at.

# Mark S. Miller (5 years ago)
Object.isz = (x, y) => x === y || Object.is(x, y);
# Olov Lassus (5 years ago)

2013/12/23 Brendan Eich <brendan at mozilla.com>

You are reasoning from general to particular, but without any reason to focus on the particular of redefining a non-writable property from -0 to +0 or vice versa. There is no use-case "there" there! I bet Mark would find that a subtle security problem.

On the topic of +0, -0 and use cases... Is it still intended that Map and Set will distinguish between these two values? I'm not sure what the use case would be but I fear the consequences. Further elaborated in < esdiscuss/2012-December/026794>.

# Domenic Denicola (5 years ago)

From: Brendan Eich [mailto:brendan at mozilla.com]

No one is discussing changing === and !==, AFAIK. Not every, in TC39.

To clarify, I was talking about previous discussions where (IIRC) some hoped to move Array.prototype.indexOf to SameValue. Those were abandoned for compatibility reasons, but I was wondering if it would be possible to move indexOf (and case matching, perhaps) to SameValueZero. Sounds like "probably no," in any case.

# Mark S. Miller (5 years ago)

No, Map and Set will equate -0 and +0.

# Mark S. Miller (5 years ago)

On Sun, Dec 22, 2013 at 3:28 PM, Brendan Eich <brendan at mozilla.com> wrote:

Domenic Denicola wrote:

If the belief is truly that SameValueZero is more useful than SameValue, perhaps we should consider relaxing that restriction, and allowing people to flip the sign of non-writable zero-valued properties?

You are reasoning from general to particular, but without any reason to focus on the particular of redefining a non-writable property from -0 to +0 or vice versa. There is no use-case "there" there! I bet Mark would find that a subtle security problem.

Yes, it opens an overt communications channel through allegedly frozen state.

# Olov Lassus (5 years ago)

2013/12/23 Mark S. Miller <erights at google.com>

No, Map and Set will equate -0 and +0.

\o/

Filed a bug

# Rick Waldron (5 years ago)

On Sun, Dec 22, 2013 at 6:41 PM, Mark S. Miller <erights at google.com> wrote:

No, Map and Set will equate -0 and +0.

In SpiderMonkey's Set and Map:

var s = new Set([-0, +0]);
s.size; // 2

var m = new Map();
m.set(-0, 1);
m.set(+0, 2);

m.get(-0); // 1
m.get(+0); // 2
# Alex Kocharin (5 years ago)

An HTML attachment was scrubbed... URL: esdiscuss/attachments/20131223/299e1d8d/attachment

# Michał Gołębiowski (5 years ago)

Chrome Canary behaves similarly (with the difference that the Set constructor can't convert an array), Olov reported an issue: code.google.com/p/v8/issues/detail?id=3069

This is probably just code based on non-recent drafts as not equating them would be bad for reasons Olov outlined in his post.

Why WeakMap/WeakSet continue differentiating between +0 and -0?

# Till Schneidereit (5 years ago)

On Mon, Dec 23, 2013 at 1:11 AM, Rick Waldron <waldron.rick at gmail.com>wrote:

In SpiderMonkey's Set and Map:

  var s = new Set([-0, +0]);
  s.size; // 2

  var m = new Map();
  m.set(-0, 1);
  m.set(+0, 2);

  m.get(-0); // 1
  m.get(+0); // 2

Filed bug 952870, patch included.

# Brendan Eich (5 years ago)

Alex Kocharin wrote:

Object.is() looks like a perfect function for checking oddballs (-0, NaN) if you want to represent an arbitrary data correctly. In that case distinguishing signed zeroes is a big plus

or absolutely required.

(making (-0).toString() === '-0' would be better though).

(Not backward compatible -- no one is going to risk this for so little gain.)

# Brendan Eich (5 years ago)

Mark S. Miller wrote:

Object.isz = (x, y) => x === y || Object.is(x, y);

Not bad.

# Alex Kocharin (5 years ago)

23.12.2013, 05:59, "Brendan Eich" <brendan at mozilla.com>:

Alex Kocharin wrote:

(making (-0).toString() === '-0' would be better though).

(Not backward compatible -- no one is going to risk this for so little gain.)

That's something I never really understood when I was reading ES5 spec, where -0 is a special case, and a sole reason why x === Number(String(x)) is not true for all numbers.

Why isn't it stringified as "-0"? How did that happen? Do somebody really check if something is less than zero using "-" in string representation?

# Brendan Eich (5 years ago)

Alex Kocharin wrote:

That's something I never really understood when I was reading ES5 spec, where-0 is a special case, and a sole reason why x === Number(String(x)) is not true for all numbers.

Why isn't it stringified as "-0"? How did that happen? Do somebody really check if something is less than zero using "-" in string representation?

That goes back to ES1, not ES5, and probably to the ur-JS implementation (Mocha, in Netscape 2). And it arose due to same outcome in C sprintf, snprintf, etc.

No language stringifies -0 as "0" that I know of. IIRC, IEEE-754 recommends against doing that. Stringizing is not for serialization, rather for human consumption in general, and -0 === 0.

# Brendan Eich (5 years ago)

IMPORTANT TYPO ALERT!

Brendan Eich wrote:

No language stringifies -0 as "0"

I meant "-0".

that I know of. IIRC, IEEE-754 recommends against doing that. Stringizing is not for serialization, rather for human consumption in general, and -0 === 0.

... jetlagged again, at least it is for vacation this time...

# Andreas Rossberg (5 years ago)

On 23 December 2013 03:17, Alex Kocharin <alex at kocharin.ru> wrote:

That's something I never really understood when I was reading ES5 spec, where -0 is a special case, and a sole reason why x === Number(String(x)) is not true for all numbers.

NaN is another special case. IEEE equality is just broken,

Why isn't it stringified as "-0"? How did that happen? Do somebody really check if something is less than zero using "-" in string representation?

Lacking true integers, that would break JavaScript's poor man's emulation of arrays.

# Brendan Eich (5 years ago)

Andreas Rossberg wrote:

NaN is another special case. IEEE equality is just broken,

... in your hardware, all of it.

Standards from the last days of Disco, like Disco, will never die.

Lacking true integers, that would break JavaScript's poor man's emulation of arrays.

C'mon, that's not the reason. Hardly anyone generates -0 as an index and expects it to index a[0] for some array a. Things to complain about! :-P

# Andreas Rossberg (5 years ago)

On 7 January 2014 15:28, Brendan Eich <brendan at mozilla.com> wrote:

Standards from the last days of Disco, like Disco, will never die.

Yes. Yet there is no reason why languages keep using it as the generic equality on floats. It could be a separate operator. Especially since comparing floats for equality is disadvised against anyway...

C'mon, that's not the reason. Hardly anyone generates -0 as an index and expects it to index a[0] for some array a. Things to complain about! :-P

It's not all that difficult to accidentally create a -0 when you do pure "integer" arithmetic with floats. I'm pretty sure it would be a major pitfall. Wasn't that the reason why we changed Map?

# Brendan Eich (5 years ago)

Andreas Rossberg wrote:

It's not all that difficult to accidentally create a -0 when you do pure "integer" arithmetic with floats. I'm pretty sure it would be a major pitfall. Wasn't that the reason why we changed Map?

Maybe, and I'm not thrilled about that change, but Map is new, and different from Array or array-likes anyway (value to value mapping).

My point was Array indexing is the least of our concerns. Changing (-0).toString() will probably break tons of code, including numeric form code, even if only showing "-0" to users who want "0".