Equality semantics and normalization
Edit: this post seems to have been based on a misunderstanding of Waldemar's proposal; see https://github.com/littledan/proposal-bigdecimal/issues/11#issuecomment-557752285 for clarification.
Combining @waldemarhorwat's previous proposal with what we have in ES6 and BigInt, I'd imagine that equality semantics may be as follows:
-
===andSameValueZerocompare the normalized values -
==,<, etc can compare BigDecimals to other numeric types, according to their mathematical values (following BigInt) -
SameValue/Object.iscompares according to the representation of BigDecimal (just one NaN, but differentiating trailing zeroes)
Does anyone have concerns with these semantics?
What's the use case for differentiation of trailing zeros in Object.is? It may be more useful to provide a function which returns the number of decimal places to compare for equivalence based on trailing zeros.
That library function sounds interesting. Maybe you could explain the semantics and motivation a bit further in #14 ?
We have a general invariant in JavaScript, that if two values are Same value/Object.is, then they are totally indistinguishable, and could be thought of as "the same value". So then we wouldn't be able to make that library function work if so.
In my intuition Object.is(0m, .0m) should return true or we should have Math.signbit to distinguish 0m and -0m (but consider 0m and .0m as equal) using n1 === n2 && Math.signbit(n1) === Math.signbit(n2). Math.sign is kind of broken because Math.sign(-0) === Math.sign(0).
On the other hand, if there will be no -0m, then it could be fine.
Decimal.js and friends do have -0. Should we create a separate issue about -0 since #9 is about non-finite values only? Negative could be useful to indicate last stock price change direction for example, though it's not a common case in my practice. Also it could be confusing if BigDecimal will have -0m when BigInt doesn't have -0n
Most use cases won't care or need to think about precision.
It's fine if a BigDecimal value can carry precision information, but this shouldn't be considered on any common paths (===, ==, Object.is, etc).
I think it'd be a pretty big change in how JS works in general if precision were distinguishable according to some library function, but the two values are Object.is. Could you say more about why they should be indistinguishable along this path, and what this would mean for equality in general?
I don't think I agree that most use cases won't care about precision. For example, trailing zeroes are useful in the money case, which I think will be extremely common. $2.5 is not really semantically meaningful, and $2.50 is.
@ljharb If you want to argue that BigDecimal should always be normalized, please file an issue arguing that; this issue is about how to handle equality on the basis of a data model which does support trailing zeros.
My argument imo applies to both; i think it would be very surprising if the same number with different precisions were sometimes distinguishable and sometimes not. Also, this isn’t a proposal for currency or money as i understand it, so the semantic meaning of $ and $2.50 don’t apply to this proposal.
In other words, if the proposal is going to consider 2.5 and 2.50 to be different, then I think so should ===, ==, toString, Object.is, etc.
@ljharb It would be helpful if you could explain where you disagree with @waldemarhorwat's previous arguments, in addition to stating your conclusion.
@littledan that's a long argument and it seems to require a lot of context, so i'm not sure what specifically i should be disagreeing with. The "Should trailing zeroes be printed when doing toString on decimal values?" question seems to assume that 0m would toString to 0 - but I don't think that's necessarily a foregone conclusion just because 0n toStrings to 0.
I do agree that trailing zeroes should not be printed, though, which seems to suggest that 5.00m and 5m would be ===. Can you help me understand what in that linked email suggests that trailing zeroes/precision should be preserved?
I strongly feel that IEEE decimal trailing zeros should not be distinguishable. You may say that someone wants to distinguish 5.00m from 5.0m, but the real trouble starts when the precision is less than the number of digits in an integer. You'd need to distinguish 1000m from the result of 2000m/2m; the latter would have one less significant digit than the former and couldn't even be printed as an integer if you wanted to retain the precision in printed form. This would get weird very quickly.