5 ms·
Along these lines: if you are designing an API for pricing data or fintech and think “let’s send things in integer cents of the currency so there aren’t any rou
by btown 5y ago
Along these lines: if you are designing an API for pricing data or fintech and think “let’s send things in integer cents of the currency so there aren’t any rounding errors” - setting aside that there are many situations where this is not appropriate, if you do still want to do this, for the love of Pete please name your variables and attributes with `_cents` in the names. No exceptions. It is the biggest unit-related footgun imaginable, and since it’s not a “unit” technically, it’s easy to overlook.
- arpa 5y agoAssuming all currencies have 2 decimal units and subunits have 1:100 ratio is another major footgun: https://en.m.wikipedia.org/wiki/ISO_4217 https://en.m.wikipedia.org/wiki/ISO_4217
- btown 5y agoAbsolutely agreed! And a more nuanced approach is what Stripe does, which is to take the "zero-decimal-currency" as the unit of record, be that USD cents or the non-subdivisible JPY. https://stripe.com/docs/currencies#zero-decimal https://stripe.com/docs/currencies#zero-decimal But in that case, and especially in that case, in any system that might interact with, say, a UI where a field is in decimal USD, Stripe needs to be careful about which things are price_decimal and price_zerodecimal. Unless you have a near-religious fervor that all variables not annotated with _decimal are assumed to be _zerodecimal, in such a situation one might go so far as to auto-reject any PR that does not suffix all variables explicitly. Because the alternative is hard-to-detect 100x-off bugs that occur when battle-tested systems/libraries are reused in different contexts.
- Archelaos 5y agoAs we all know, naming things is so difficult. Most currencies do not have "Cent" as a base unit. And there are currencies without a smaller base unit, most notably japanese Yen. The problem is, that there exists no established currency neutral name to distinguish between the two possible units that coincide in such cases as Yen. I was thinking about the following: class AmountOfMoney property int FinerAmount property decimal CoarserAmount In the case of Yen (FinerAmount == CoarserAmount) is always true. Any suggestions for better wordings?
- gpderetta 5y agoSplitting the integer and the decimal part is always annoying because now you have to deal with non-normalized quantities. An option is to just use a custom float type: class AmountOfMoney int mantissa int exponent # base 10
- Archelaos 5y agoThis is a missunderstanding. If we have for example USD 10.42, the values in my implementation are: FinerAmount = 1042 CoarserAmount = 10.42 The profile of the class was abbreviated. Of course, we also need a currency property for the general case: Currency = USDollar The definition of the class for the currency in pseudo-code: class Iso4217CurrencyCode int NumericCode string AlphabeticCode int DecimalPlaces static USDollar = new Iso4217CurrencyCode(840, "USD", 2); static Yen = new Iso4217CurrencyCode(392, "JPY", 0); The constructor for the amount of money only uses FinerAmount, and CoarserAmount is calculated: CoarserAmount => Convert.ToDecimal(FinerAmount / Math.Pow(10, Currency.DecimalPlaces)); So foo = AmountOfMoney(FinerAmount: 1042, Currency: USDollar); sets foo.CoarserAmount automatically to 10.42. But bar = AmountOfMoney(FinerAmount: 1042, Currency: Yen); sets bar.CoarserAmount automatically to 1042.