Kotlin Money
Kotlin Money is a library for Kotlin that simplifies monetary calculations, supports traditional and cryptocurrencies, prevents rounding errors, and plans future enhancements, including Android support and improved functionality.
Read original articleKotlin Money is a new library designed to simplify monetary calculations in Kotlin, addressing the lack of a first-class data type for money in mainstream programming languages. The library allows developers to perform mathematical operations with monetary amounts, handle percentages, and allocate funds accurately, which is crucial for applications involving installment payments, foreign exchange, and fee processing. It supports both traditional currencies and cryptocurrencies, enabling seamless transactions and calculations. A key feature of Kotlin Money is its allocation capability, which ensures that the sum of allocated parts equals the original amount, thus preventing rounding errors that can lead to financial discrepancies. The library is built to be user-friendly, with a concise API and support for a wide range of currencies and cryptocurrencies. Future updates will aim to enhance its functionality, including support for Android development and improved persistence and serialization options. Developers are encouraged to explore the library and its usage guide for implementation in their projects.
- Kotlin Money library simplifies monetary calculations in Kotlin.
- It supports both traditional currencies and cryptocurrencies.
- The library prevents rounding errors through its allocation feature.
- Future updates will enhance functionality and support for Android.
- Developers can refer to the usage guide for implementation details.
Related
LLVM Libc now has all C23 basic math functions for all 5 floating point types
The LLVM C Library offers accurate mathematical functions compliant with C and IEEE 754 standards, supports multiple data types, and shows competitive performance across various platforms, allowing user contributions.
Kotlin for Data Analysis
Kotlin provides tools for data analysis, including Kotlin notebooks and DataFrame, enabling users to load, transform, visualize data, and integrate with databases, enhancing data science and machine learning capabilities.
- Many users are curious about handling edge cases, such as small decimals and rounding rules in monetary calculations.
- There is a discussion about the API design, with some preferring more conventional methods over infix functions.
- Several comments highlight the importance of distinguishing between different currencies to avoid unit confusion.
- Users express interest in the library's internal modeling of monetary values and how it manages rounding and precision.
- Some commenters compare Kotlin Money to similar libraries in other languages, emphasizing the need for robust currency handling across programming ecosystems.
The use of infix functions reads a bit weird to me.
If I were to design an API like this in Kotlin, I think I would have gone for regular extensions for many cases and perhaps extension properties, think as such:
val fiveBucks = 5.usd
val fiveBucks = 5.money("USD")
val tenPercent = 10.percent
How come you went for "increaseBy" and "decreaseBy" instead of overloading `plus` and `minus`? Just curious, preference is a valid answer.1) A hint about potential prior art: F# (and/or C#?) have a first-class unit system (physical units I think), which sounds a bit similar to monetary calculations. However, physical unit are easier to model than monetary unit I think.
2) Currently, I am building something tangentially related in Rust: A backtester (test trading strategies on historical and/or simulated data) with focus on accuracy. So one thing I included already is that Assets (like etfs) are valued in a currency.
If I may be so bold: How would you approach these questions / where could I read more about that? 1) When simulating, can I always assume that the exchange will work? (For assets, that is not always the case, sometimes one has to wait a bit until there is a buyer, or there might not be a buyer at all) 2) Is there public domain data in exchange rates? 3) If I have to choose, which exchange rate should I pick? The lower one, higher? What would make the most sense in the context of trading etfs, stocks, options, crypto etc.? 4) How to approach rounding, is there a best practise? 5) I assume it is best to immediately substract taxes in every transaction, even if they are formally defined annually, right? 6) Would you model inflation? I currently plan to ignore it and present it at the very end: "Your portfolio has a final value of X.X ¥. Adjusted for inflation, that would be Y.Y ¥ today (2024-10-08)."
On the other hand, be careful about tying the symbol to the currency, as symbols are locale specific. For example, the symbol for USD is $ in eu-US but US$ in en-CA and en-AU (Canada and Australia), and then $US in French locales.
https://cldr.unicode.org/ is the magical dataset behind most good implementations that deal with currency display. Updated twice a year, available in JSON, providing currency symbols and formatting rules for all locales, as well as country => currency mappings and other useful information.
Disclaimer: I maintain a Go solution in this problem space: https://github.com/bojanz/currency
https://www.rebol.com/docs/core23/rebolcore-16.html#section-...
> $100 + 11 $111.00
> $10 / .50 $20.00
In general, Rebol's type system was very expressive. Would love to see more libraries like this provide that type of experience.
Tangentially, I also often think about super-strict typing. I know people mention some languages that already do this sort of thing (Units of Measure in F# was talked about). It seems silly to me that so many low level programming languages still use uint64, size_t, or char equivalents for the vast majority of the code. Why not `celsius` vs `farenheit`? Or `meters` vs `feet`. That would stop a lot of possible errors. And even more so, if the language supported things like (2 feet * 2 feet) = (4 square feet). Or (10 meters / 5 seconds = 2 m/s).
Looks cool, always happy to see Kotlin love!
- Let's say I load two money values from a database. Value A is 1 USD and value B is 1 BTC. If I try to add them together, what happens? (I would expect a runtime exception. In fact, I would hope for a runtime exception, because the operation usually indicates a programming error.)
- If I divide $2.00 by 3, do I get $0.66 or $0.67? If I want to specify the rounding rule, is there a simple way to do it? I see there's support for allocation by percentage, but sometimes the allocation rules are more complex and I need to be able to specify the rounding rule.
- Does this library help parse user input? When parsing user input, what happens to extra digits? Does "0.015" get interpreted as $0.01 or $0.02?
Edit: one more question. Sometimes people bend the rules on the number of digits; for example, gas stations may charge $3.599 per gallon. Can the library deal with that or would I have to convert to decimal, multiply, and then convert back to money?
[0] https://cs-syd.eu/posts/2022-08-22-how-to-deal-with-money-in...
[1] https://www.reddit.com/r/java/comments/wmqv3q/standards_for_...
[1] https://jcp.org/en/jsr/detail?id=354 [2] https://javamoney.github.io/
Manipulating money is probably trickiest thing since time was invented. Library looks very usable.
I have to ask though:
> val transactionFee = 1.25.percent() // 1.5%
How is it 1.5?
The 'money/percent/usd' are almost like new keywords - which to me seems bad. Why not a formatter or another tool that simplifies but doesn't make it too clever or worse, hard to read.
Kotlin is really cool and arguably better than Java. But the language is very hard to read ('easy' to write). And with so many different ways of doing a single thing (and many of them exist to support Java, I understand) plus new 'macro-like' things expanding the language automagically makes it very hard to grasp.
I hope I am not the only one with this same feeling...
[1] https://ada-lang.io/docs/arm/AA-F/
[2] https://www.adaic.org/resources/add_content/standards/22rm/h...
Visual Basic 6 and VGA had a `Currency` type (replaced by `Decimal` in VB.NET): https://learn.microsoft.com/en-us/office/vba/language/refere...
T-SQL has `money` and `smallmoney` types: https://learn.microsoft.com/en-us/sql/t-sql/data-types/money...
...am I missing something?
This looks like it's ignoring the Number and creating a new Money object (of denomination 1?)
> public infix fun Number.money(currency: String): Money = money(currency, defaultRoundingMode, null)
However, the Kotlin code looks absolutely… wrong? Strange? It just feels like a lot of magic to end up with ugly code.
This is all subjective, so my question is only this: is this how Kotlin is like in 2024?
Parcal has a Currency type. Though, I can understand not calling it mainstream... Fun fact it's a fixed point type which is just a Int64 behind the scenes, at least in Delphi.
val price = 100 money USD
Note the lack of quotes around USD.I had an idea for a fixed-decimal class (that would also be useful for a money class) that held all inflight amounts as fractions and only did the division and float rounding when you needed to view the amount.
- fixed point arithmetic
- tagging values with units
- localization for parsing currency names into units
I'm curious if Kotlin's type system is expressive enough to allow you to catch at compile time cases where you might be trying to, e.g. add USD to GBP.Edge case?
I want to calculate the installments of 265 Wei (0.000000000000000265 ETH) over a period of 144 months
This one seems to carry units, as in, it is not a type with math for a known amount of fixed point precision that differentiates this library, but that it captures that plus the unit -- the currency, USD, EUR, etc -- that it is in.
It was fun writing the extra pennies distribution logic tho
I am the author of a similar crate in the rust ecosystem: https://crates.io/crates/currencies
major features include:
* support for all ISO-4217 currencies (though not all have been explicitly tested as it is hard to find native users of some)
* compile-time macros for specifying an Amount in the native format (with symbol, etc)
* support for non-base-10 number systems (there are a few ISO currencies that needed this)
* every currency uses an appropriate backing data type, and new currencies and backing data types can be defined as long as they meet the trait requirements
* opt-in ability to enforce only checked math ops (but using the usual +,/,-,* etc symbols). This is critically important for crypto and finance applications where a panicking math op can, for example, brick a blockchain or real-time trading system
* support for parsing and printing currencies in their native format at runtime
* currencies use the appropriate format style (https://github.com/sam0x17/currencies/blob/main/core/src/cur..., i.e. symbol can be "suffix attached", "suffix spaced", "prefix attached", "prefix spaced")
* support for a number of cryptocurrencies, basically popular ones and ones I've bothered to add. Will always accept PRs adding others!
* ability to define your own currencies using the `define_currency!` macro. Though these will not be supported by the built-in `amt!` macro unless I add them to the crate.
e.g., here is how a few of the core currencies are defined:
define_currency!(USD, u64, 1_00, "$", "United States Dollar", PrefixAttached, true, false);
define_currency!(BTC, u64, 1_00000000, "BTC", "Bitcoin", SuffixSpaced, false, true);
define_currency!(ETH, U256, u64_to_u256(1_000000000000000000), "ETH", "Ethereum", SuffixSpaced, false, true);
One disadvantage right now is there is no ability to have a generic "amount of some arbitrary currency" other than through generics, as the underlying traits aren't object-safe. A good way to work around this is to define an enum that contains all the currencies you plan to support. I am working on a feature that will let you easily generate this enum at compile-time :)
parsing is done using my Quoth parsing crate which provides a very safe, lexer-less way to do parsing of UTF-8 strings that relies on recursive parsing in a way somewhat similar to syn, but there are no token streams https://crates.io/crates/quoth
I don't think that's correct, absent some no-true-scotsman gymnastics.
F# has units-of-measure (UoM) out of the box, and it supports decimal numbers. I've come across a python library for UoM as well.
The big problem with handling money in code is not, IMO, the rounding (your allocate function is a nice utility but it's not core); it's unit confusion - adding baht to ren mi bi, adding cents to euros, etc. This problem is very well solved by F#'s UoM.
I beg to differ. Java has "Decimal" class which guarantees to be safe from IEEE754 floating number side effects, and specially created to handle cases like money and financial calculations.
In these days it's used as BigDecimal, it seems [1].
[0]: https://docs.oracle.com/javase/8/docs/api/java/text/DecimalF... [1]: https://docs.oracle.com/en/java/javase/23/docs/api/java.base...
This is literally the entire point of COBOL
Is it functional , OOP or something else, which paradigm does it represent?
I always has used integer data type and counted cents. Why need this?
eth is whole number 10*18. usdc is 10*6.
usd is if to speak is 10*2 number.
solana eth price is less than eth eth price because of bridge risk.
etc.
there are on decimal money to out of crypto.
there are logarithmic money in crypto.
so many many moneys.
Related
LLVM Libc now has all C23 basic math functions for all 5 floating point types
The LLVM C Library offers accurate mathematical functions compliant with C and IEEE 754 standards, supports multiple data types, and shows competitive performance across various platforms, allowing user contributions.
Kotlin for Data Analysis
Kotlin provides tools for data analysis, including Kotlin notebooks and DataFrame, enabling users to load, transform, visualize data, and integrate with databases, enhancing data science and machine learning capabilities.