Issues relating to 9.11 The SameValue Algorthm

Allen Wirfs-Brock Allen.Wirfs-Brock at microsoft.com
Thu Nov 13 17:38:01 PST 2008


From: Mark S. Miller [mailto:erights at google.com]
>>I also think the SameValue name is misleading as it is really just a StricterEquality test and not a identical value test.  This name confusion is probably what caused it to be edited into [[DefineOwnPropety]].
>As DavidSarah says, SameValue *is* an identical value test. The only difference between === and an identical value test is NaN and -0, which are therefore called out as special cases in SameValue.

There is at least one case where it is not an identical value test.  That is the case where there are multiple implementation dependent NaN encoding as is explicitly allowed for by the specification. Even though == and ===  (and SameValue) does not distinguish them they are potentially distinguishable by a host object or otherwise using external code ad this distinction can be reported back to ECMAScrpt code.  As such, they don't meet my usual criteria as being identical values and in particular I would consider an apparent attempt to use Object.defineProperty to replace a readonly NaN value with a different NaN value encoding to be a violation of the [[Writable]]: false constraint.  That's why I don't believe it is appropriate to use SameValue in [[DefineOwnProperty]] .


>From: David-Sarah Hopwood

>

>> I have no idea what Decimal compareQuietEqual actually does but I

>would also

>> assume that it does something other than an exact same encoding

>comparison.

>

>SameValue checks the NaN and zero cases first before using

>compareQuietEqual.

>


My concern (and question) about compareQuietEqual was whether or not it ever returns true for values with distinct representations (for example zeroes with different precisions) that are potentially observably different in some aspect from either external code or ECMAScript code. I don't know that it does but I can imagine that it might.



>NaNs (binary and decimal) with distinct internal representations are

>not supposed to be observably distinguishable by ECMAScript code; see

>section 8.5. That is, the *same* NaN value at the ECMAScript level can

>have different representations at the implementation level (just as it

>is possible that the same function value might have different

>representations, or a representation that changes if the function is

>dynamically compiled, etc.)

>

As I've said above, I think observably different via calls to external code is enough to call into question the sameness of two values. This is particularly the case when we are dealing with primitive data types  like binary and decimal floats that routinely flow across language or other domain boundaries. I'm not particularly concern about language specific types and values (for example, a language specific closure type) that is unlikely to be passed or have meaning across such boundaries. Obviously, an implementation should be free use alternative encoding for the "same" value but it probably needs to cannonicalize such representations when passing them outside its private implementation domain. Unless we require canonicalization for primitive values on calls to/from host objects we probably need to be a little less parochial about what is observable.


From: Mark S. Miller [mailto:erights at google.com]
Sent: Thursday, November 13, 2008 12:56 PM
To: Allen Wirfs-Brock
Cc: es3.x-discuss at mozilla.org; es-discuss at mozilla.org
Subject: Re: Issues relating to 9.11 The SameValue Algorthm

On Thu, Nov 13, 2008 at 10:31 AM, Allen Wirfs-Brock <Allen.Wirfs-Brock at microsoft.com<mailto:Allen.Wirfs-Brock at microsoft.com>> wrote:

OK, I now see the difference between SameValue and StrictEquality.  SameValue(NaN,NaN) is true and StrictEquality(NaN,NaN) is false.  Assuming that we really need this distinction, rather than duplicating "code" I would define one in terms of the other with an additional predicate to handle the NaN distinction.
Yes. And StrictEquality(0, -0) is true whereas SameValue(0, -0) is false. (This is modulo a possible Word rendering error in the Kona draft. This difference on -0 is certainly what was intended, and what I sent to Pratap.)




I also think the SameValue name is misleading as it is really just a StricterEquality test and not a identical value test.  This name confusion is probably what caused it to be edited into [[DefineOwnPropety]].
As DavidSarah says, SameValue *is* an identical value test. The only difference between === and an identical value test is NaN and -0, which are therefore called out as special cases in SameValue.



Finally, I understand the thinking behind using SameValue in Array.prototypeindexOf and Array.prototype.lastIndexOf but do we really want to introduce yet another concept of "equality" into the language just to these functions.  If NaN comparision is a special case for these function might not there be other special cases of user defined objects?  To me, a better design would be to add a optional third  argument to those functions which is a closure that provides the comparison function.  That way the default comparison could be === (or == if that makes more sense) and you would search for a NaN by saying something like: [1,2,NaN,3].indexOf(NaN,0,function(x,y) {return IsNaN(x)}).  Of course, the first argument is not strictly necessary in this formulation so an even cleaner alternative might me findIndexOf(callbackfn [, fromIndex]) so you could express it as [1,2,NaN,3].FindIndexOf(function(x,y) {return IsNaN(x)})

There's some sense to adding a third argument, but let's not try to squeeze that into ES3.1. In its absence, the default should SameValue, not StrictEquality. These are operations on collections, and should be consistent with the behavior we expect to specify for future containers, specifically Maps.



So, what do the "in the wild" implementations of indexOf do?  Do they do a === comparison or do they do the equivalent of the proposed SameValue function?
They do a === comparison. We have recently switched Caja's indexOf and lastIndexOf to SameValue. This change has not disrupted our attempts to port the Prototype and jQuery libraries onto Caja. Nor has it triggered any failures in their regression tests. To accumulate more data, I encourage all those in a position to test to add the following code to some relevant prelude:

(function(){

  function identical(x, y) {
    if (x === y) {
      // 0 === -0, but they are not identical
      return x !== 0 || 1/x === 1/y;
    } else {
      // NaN !== NaN, but they are identical
      return isNaN(x) && isNaN(y);
    }
  }

  Array.prototype.indexOf = function(specimen) {
    var len = this.length;
    for (var i = 0; i < len; i += 1) {
      if (identical(this[i], specimen)) {
        return i;
      }
    }
    return -1;
  };

  Array.prototype.lastIndexOf = function(specimen) {
    for (var i = this.length; --i >= 0; ) {
      if (identical(this[i], specimen)) {
        return i;
      }
    }
    return -1;
  };
})();


Thanks.

--
   Cheers,
   --MarkM
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20081113/1f033724/attachment-0001.html>


More information about the Es-discuss mailing list