tc39 / proposal-decimal

Built-in decimal datatype in JavaScript

Home Page:http://tc39.es/proposal-decimal/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Object with operator overloading + literals?

littledan opened this issue · comments

In the February 2020 TC39 meeting, @erights and @kmiller68 suggested that decimal may have the semantics of an object with operator overloading and extended literal syntax, following the proposals for each. This is partly inspired by @kmiller68's assessment of the complexity of adding new primitives (from both a design and implementation perspective, with a possible "slippery slope" of many new primitives) and @erights' assessment that it may be difficult to add user-defined value types to JS (due to conflicting requirements around a cross-realm value type registry).

When I discussed this idea with @BrendanEich, he raised several concerns about object semantics:

  • In the operator overloading proposal, === may not be overloaded. Instead, records and tuples and potential future value types proposals make forms of compound values which are the same, and compare as equal. Part of this would be to not expand beyond -0 and NaN the set of values which are not the same by Object.is but are the same by ===.
    • Impact for decimal: If decimal is an object, then multiple decimal objects could have the same value, but not be ===. Developers would have to use == to compare decimals instead, needing to unlearn the advice they've gotten about not using ==.
  • Maps and Sets work by Object.is and don't permit other hash functions. The collection normalization proposal would let collections be keyed by other values; for decimals, keying a map by the .toString() value would probably work well.
    • Impact for decimal: Maps keyed by decimals would be keyed by their object identities, rather than values as developers may expect, though this could be mitigated with the collection normalization proposal.
  • The set of falsy values is fixed, and no method is called for conversion to boolean. All objects are truthy. The operator overloading propsoal does not propose to ch
    ange this, though Brendan has proposed that value types be able to define more falsy values.
    • Impact for decimal: if (0m) would take the true branch, for decimals, which would not match expectations people may have that decimals behave like Numbers in this respect.

Are these impacts worth it? It seems to me like decimals as objects rather than primitives would be suboptimal for JS developers, but probably significantly better than not adding the feature.

Great analysis! Fair enumeration of pros and cons. The key issue for me is that decimal will be only one of many upcoming numeric or numeric-like types, by which I mean, types that overload the arithmetic operators with arithmetic-like meaning, i.e., that satisfy many of the algebraic identities that we expect of these operators.

  • matrices
  • rational
  • complex
  • unit typing, i.e., 3@seconds + 4@meters should be a type error
  • set-ish (+ is union, * is intersection, <= is subset, == is enumeration order independent)
  • amounts of erights

So I am against doing something for decimal that is not equivalent to what future JS programmers will be able to do for themselves with these others. That doesn't mean we don't eventually make some kind of special case for decimal, such as building it into the language. But it means we do it after we add general operator overloading and implement decimal as a library using it.

It also does not necessarily mean that these are all objects, though it probably does. All of those above would have liked to be value types rather than objects if we could figure out a good general value types proposal. In E, all of these would have been "Data" objects rather than normal objects. E "Data" has the characteristics:

  • transitively immutable
  • transitively identity-free
  • only structural equality for our equivalent to ===
  • perfectly pass-by-copy, i.e., unserialize(serialize(x)) === x

But, like Dan says, I doubt we'll be able to figure out general value types for JavaScript. Dan's operator proposal shows we can get most of the benefits for object types. I think we should.

Regarding money, Agoric would never use decimal for it anyway, even if it were in the language. To us, the only good representation for money is BigInt, in terms of the smallest possible tradable atomic unit of a given currency. The only problem with a BigInt representation is its printed form, on both input and output. For this, if we had operator overloading, we'd build an object around a BigInt that had the additional desired formatting knowledge. == on these would check that they are the same amount of the same currency but ignore formatting differences.

@erights Are you saying, we should take all of the tradeoffs above (=== not useful, Maps/Sets counter-intuitive, and always truthy) for decimals? Beyond consistency properties of the language, how should we judge whether this tradeoff is appropriate?

Could we discuss use cases in #52 rather than this issue? ("smallest possible tradeable atomic unit" is not always so well-defined for currencies, but I'd like to dig into this elsewhere.)

Are you saying, we should take all of the tradeoffs above (=== not useful, Maps/Sets counter-intuitive, and always truthy) for decimals?

yes

Beyond consistency properties of the language, how should we judge whether this tradeoff is appropriate?

I am arguing from consistency. If all the others will need to suffer these problems, why not decimal too?

Hi Mark, sorry to barge in late. We have been talking about value types on and off (more off than on in my case, apologies) for years, so have some context not everyone else has. Dan and I are talking about writing it down, but until then, I'd like to leave my two cents on not deciding yet for Decimal that Object is the only way to go. Consistency has many dimensions with trade-offs among them, and if we can get our value types proposal together, perhaps Decimal (after BigInt, after number/string/boolean/symbol) can be a value type and people expecting consistency along the "numeric" dimension win.

I'm fine with continuing to try to get general extensible value types working. If we do, do you agree that the above bulleted examples of things that would overload operators while maintaining algebraic identities should then be written as value types? If we decide to go this route, I would still like to wait until decimal has actually been implemented this way before considering more direct support for it.