Revisiting Decimal (generic algorithms)

Sam Ruby rubys at intertwingly.net
Fri Jan 16 16:30:18 PST 2009


On Fri, Jan 16, 2009 at 3:11 PM, Brendan Eich <brendan at mozilla.com> wrote:
> On Jan 16, 2009, at 11:16 AM, Allen Wirfs-Brock wrote:
>
>> Returning to  Brendan's original question...
>
> Thanks, this is a very informative reply.

Indeed.  This is the first time I understood (at a high level) the
request.  I'm not saying it wasn't explained before, or even that it
wasn't explained well, but this is the first time I understood it
(again at a high level, questions on details below).

>> [much good stuff deleted]
>
>> This problem cannot be fixed simply by tweaking the coercion rules.  It
>> probably requires that numeric literals be treated as generic values that
>> are only interpreted situationally as either binary or decimal values in the
>> context of a particular operations.
>
> That, or multimethods so we don't essentially carry around literals in
> source form and pay high costs converting them according to context. That
> was the ES4 solution at one point, until we started cutting. Based on Dylan
> and Cecil precedents:

Like Allen says later, most small integers (i.e., the ones that fit
exactly in a double precision binary value) can simply be retained as
binary64.  I suspect that covers the majority of constants in deployed
javascript.  Now let's consider the rest.

First, Allen's example:

function fuzz(a) { return a + 0.1}

Where fuzz(0.1)===0.2 and fuzz(0.1m)===0.2m

The only way I can see that working is if the constant is initially in
a form that either is readily convertible to source, or stores both
values.  I don't understand how multimethods (on "+"?) affect this.
If I'm missing something, please let me know (or simply provide a
pointer to where I can educate myself).

Continuing on, let's tweak this a bit.

function fuzz(a) {var b=0.1; return a+b}

I would suggest that if the expectation would be that this function
behaves the same as the previous one.

My interpretation is that this means that internally there are three
data types, one that is double, one that is decimal, and one that
somehow manages to be both.  Internally in that this implementation
detail ideally should not be visible to the application programmer.
Again, I could be wrong (in the need for three data types, not on the
opinion that this should not be visible), but pressing on...

function is_point_one(a) {var b=0.1; return b===a}

Is the expectation that this would return true for *both* 0.1 and
0.1m?  This leads to a rather odd place where it would be possible for
triple equals to not be transitive, i.e. a===b and b===c but not
a!===c.  That alone is enough to give me pause and question this
approach.

Continuing trip down this looking glass, what should typeof(0.1)
return?  You might come to a different conclusion, and again I might
be missing something obvious, but if these Schrödinger's catstants
(sorry for the bad pun) can be assigned to variable, then I would
assert that typeof(0.1) and typeof(0.1m) should both be 'number'.

Finally, this has bearing on the previous json discussion.  If it is
possible to defer the binding of a literal value to a particular
variant of floating point (i.e., binary vs decimal), then there no
longer is no need for a JSON parse to prematurely make this
determination.

I suspect that these last two paragraphs will make Kris happy.

But I'll stop here.  I may very well be out in the weeds at this
point.  But my initial take is that this approach produces a different
(and somehow more fundamental) set of surprises that the approach than
we had previously agreed on, and furthermore it isn't clear to me that
this approach can be implemented in a way that has negligible
performance impact for applications that never make use of decimal.

But I hope that one or both of you (or anybody else) can point out
something that I'm missing.

- Sam Ruby


More information about the Es-discuss mailing list