Which datatype to use for attributes representing money (Mx 5.14 and up)

4
Since Mendix 5.14 it is unclear which datatype to use for attributes representing money. The previous version of the reference guide clearly states that the currency datatype is meant for money. The new reference guide explicitly advices us not to use this datatype for money. The currency datatype is still available, which is rather confusing. Questions: Is the currency datatype only available for backwards compatibilty and will it become obsolete in the next version? What is the issue with the currency datatype? We certainly don't need an 8 digit accuracy for our money attributes. The are some issues in 5.14 preventing us to upgrade to this version. Is there any risk for applications that still run older versions than 5.14?
asked
3 answers
4

Thanks Jasper and Alexander for the explanation. But it would be nice if the currency datatype could stay in the Mendix platform because it becomes immediately clear what this entity means. It would be very nice if Mendix could do the rounding for me and I do not have to worry about it as a developer. So it would be more like the Excel cell properties financial. I only have to set the decimal (number of digits) and the currency symbol and I am good to go.

Regards,

Ronald

answered
9

The R&D department has to get back on the plans for potential deprication or changes on existing functionality but I can already start by explaining some of the behavior of the Mendix Platform.

What Alexander mentions about the Decimal and Float is correct. By default if you are working with money (were perfect accuracy is a must) you should use the decimal.

In Mendix an attribute of type Float has been implemented as a Double for a long time already. Every internal action on a Float field is always considered a Java Double. Both are considered floating-points, and for the rest of my explanation to keep it simple I'm ignoring any difference between a Float and Double.

The Currency attribute is not much more than a Float (Double) attribute with a default Display Mask so you'll always see two decimals.

The new field Decimal is stored as the Java type BigDecimal. This attribute type guarantees the scale and precision of all values on the right side of the decimal point (neither the Float nor a Double offer this guarantee).



There is a down side to this accuracy, the double and float are simple primitive types that have little overhead in memory or when used in a calculation. When you perform any mathematical expressions Java will simple perform that expression on the bytes to increase the speed of the calculation.
This is great because the calculation has a result faster, but because of the limited options of expression a value in bytes some numbers can simple not be expressed in a double. For example if you would perform the following calculation: 362.2 - 362.6, the outcome would be -0.4000000000000341. Those last 3 digits are introduced because of inherit nature of how floating points are stored in the Java Memory.
The only solutions to prevent getting these additional decimals is to start working with different attribute Types. Rounding the result back to 1 or 2 decimals will ultimately provide you with the same problem, when the outcome of the round is stored in the Float it re-introduces the additional decimals.
The more digits you'll introduce the bigger the change that a Float will inaccurately display and store the value. The BigDecimal is always accurate, Mendix stores the BigDecimal up till 28 digits, 20 digits before the decimal point and 8 after the decimal point. Any calculations in memory have an infinite nr of decimals.

I have only seen this introducing issues up till 3 digits behind the decimal. So for most calculations a difference of less than .001 can be acceptable, if I'm calculating the average login attempts for my app I don't really care about the 4th number behind the decimal point. But for financial calculations a common .001 difference can become a real issue.


For those scenario's where every single digit is important the type BigDecimal can be used. Unlike the floating-points, the BigDecimal guarantees the numbers to be completely accurate for every calculation.
That sounds like something you always want to have, there are some more Java specific technical drawbacks but those are irrelevant for Mendix.

Why wouldn't you always use the BigDecimal then, what can be wrong with being precise in every calculation?
I can't think of a reason why being too precise is bad, but since the BigDecimal offers you more functionality than the floating-point it will also require more resources from your environment.
In other words the BigDecimal is slower and consumes more memory. The Mendix memory structure for all attribute types is identical.


When we look at the double, that type consume just 16 bytes to store the value in memory.
A BigDecimal needs 32 bytes. That means that when you replace all your floats and currencies with BigDecimals your memory usage could increase. Also to guarantee the precision the BigDecimal will have to perform additional actions. Every action takes time so any calculations you make will take slightly longer.
This page gives a good (technical) explanation on the difference between floating points and BigDecimals.
[tl;dr] when performing the same math expression 100 million times, a double completes in .6 seconds a BigDecimal needs 4.9 seconds. So a double can be an average of 0.000043 nano seconds faster per calculation.





So when should you use the BigDecimal?   For all monetary fields.
When to use a Currency?   In the new release I wouldn't recommend using Currency anymore.
When to use a Float (Double)?   For all other situation where you don't need a guaranteed decimal precision. (I haven't run into a situation recently where I would want to use the Decimal other than for financial calculations)

answered
3

I would use the new decimal datatype for things like monetary amounts.

The currency datatype in Mendix is a floating point (same as float; confusingly both are actually a double in Java). Floating points are an approximation of real numbers, which can lead to unexpected results in certain situations if you don't know how computers do floating point calculations. See this Wikipedia page for some examples where accuracy of floating points can be a problem.

I would even argue that in almost all use cases in Mendix you don't need floating points (users cannot enter them in the UI anyway), and in hindsight the float and currency datatypes should never have been added to Mendix in favour of decimal.

answered