Fable
Fable copied to clipboard
System.Decimal.TryParse behaves differently in .NET and Fable
Description
In some locales, strings representing decimal numbers sometimes have thousands separators. For example, the number 4242 might sometimes be written as 4,242 in the UK. This is parsed correctly in F# interactive, but fails to parse in Fable.
This poses some challenges when trying to share code between client and server in SAFE apps.
Repro code
Evaluating System.Decimal.TryParse "4,242" in FSI gives the value it: bool * decimal = (true, 4242M).
The Fable REPL equivalent demonstrates the error.
Expected and actual results
Expected: (true, 4242M)
Actual: (false, 0M)
Related information
- Fable version: 4.1.3
- Operating system: REPL in Brave browser on Ubuntu 22.04
Obviously a quick fix in this case, would be to strip commas, but that has implications for other locales (for example Germany) where commas are used as the decimal separator and full stops are used as thousand separators.
For example, the number represented in the UK as 4,242.42 could be represented in Germany as 4.242,42
There may well be additional cases where parsing behaves differently; I haven't done an exhaustive check.
This one is tricky because Fable, tries to avoid supporting globalisation in general because it is difficult to implements as their are a lot of variant.
The code responsible for Decimal.tryParse is located at
https://github.com/fable-compiler/Fable/blob/ac4d44997f69d5b1b7109730ccb45e354a4ec368/src/fable-library/Decimal.ts#L124C8-L131
It is using a custom big.js implementation.
I don't see an easy way to fix this issue as it would probably requires to implement different rules based on the detected country of the user. I believe this is done nowhere else in Fable.
@mattgallagher92 If I'm not mistaken, currently Fable only supports the InvariantCulture, similar to what JavaScript number parsing supports.
Thanks both. I guess as a workaround then, I could remove commas if I know that they are being used as thousands separators. Let me know if you have a better suggestion.
Another suggestion is to look in the JavaScript ecosystem if there is a library supporting the features you need.
You can use it just to parse the user input and then pass it to Fable decimals if precision is required or for network serialisation.
Thanks Maxime, I'll investigate.
Quick question before we close the issue: is this difference documented anywhere? I didn't see it on https://fable.io/docs/dotnet/compatibility.html or https://fable.io/docs/dotnet/numbers.html.
If it's not documented elsewhere, would you like me to raise a PR to add a note to one of those pages?
I don't think it is explicitly mentioned on the documentation.
I know that if you try to pass the Globalization arguments then Fable log a warning.